OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of ssa; | 5 part of ssa; |
6 | 6 |
7 abstract class HVisitor<R> { | 7 abstract class HVisitor<R> { |
8 R visitAdd(HAdd node); | 8 R visitAdd(HAdd node); |
9 R visitBailoutTarget(HBailoutTarget node); | 9 R visitBailoutTarget(HBailoutTarget node); |
10 R visitBitAnd(HBitAnd node); | 10 R visitBitAnd(HBitAnd node); |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 } | 254 } |
255 | 255 |
256 visitInstruction(HInstruction instruction) {} | 256 visitInstruction(HInstruction instruction) {} |
257 | 257 |
258 visitBinaryArithmetic(HBinaryArithmetic node) => visitInvokeBinary(node); | 258 visitBinaryArithmetic(HBinaryArithmetic node) => visitInvokeBinary(node); |
259 visitBinaryBitOp(HBinaryBitOp node) => visitBinaryArithmetic(node); | 259 visitBinaryBitOp(HBinaryBitOp node) => visitBinaryArithmetic(node); |
260 visitInvoke(HInvoke node) => visitInstruction(node); | 260 visitInvoke(HInvoke node) => visitInstruction(node); |
261 visitInvokeBinary(HInvokeBinary node) => visitInvokeStatic(node); | 261 visitInvokeBinary(HInvokeBinary node) => visitInvokeStatic(node); |
262 visitInvokeDynamic(HInvokeDynamic node) => visitInvoke(node); | 262 visitInvokeDynamic(HInvokeDynamic node) => visitInvoke(node); |
263 visitInvokeDynamicField(HInvokeDynamicField node) => visitInvokeDynamic(node); | 263 visitInvokeDynamicField(HInvokeDynamicField node) => visitInvokeDynamic(node); |
264 visitInvokeUnary(HInvokeUnary node) => visitInvokeStatic(node); | 264 visitInvokeUnary(HInvokeUnary node) => visitInstruction(node); |
265 visitConditionalBranch(HConditionalBranch node) => visitControlFlow(node); | 265 visitConditionalBranch(HConditionalBranch node) => visitControlFlow(node); |
266 visitControlFlow(HControlFlow node) => visitInstruction(node); | 266 visitControlFlow(HControlFlow node) => visitInstruction(node); |
267 visitFieldAccess(HFieldAccess node) => visitInstruction(node); | 267 visitFieldAccess(HFieldAccess node) => visitInstruction(node); |
268 visitRelational(HRelational node) => visitInvokeBinary(node); | 268 visitRelational(HRelational node) => visitInvokeBinary(node); |
269 | 269 |
270 visitAdd(HAdd node) => visitBinaryArithmetic(node); | 270 visitAdd(HAdd node) => visitBinaryArithmetic(node); |
271 visitBailoutTarget(HBailoutTarget node) => visitInstruction(node); | 271 visitBailoutTarget(HBailoutTarget node) => visitInstruction(node); |
272 visitBitAnd(HBitAnd node) => visitBinaryBitOp(node); | 272 visitBitAnd(HBitAnd node) => visitBinaryBitOp(node); |
273 visitBitNot(HBitNot node) => visitInvokeUnary(node); | 273 visitBitNot(HBitNot node) => visitInvokeUnary(node); |
274 visitBitOr(HBitOr node) => visitBinaryBitOp(node); | 274 visitBitOr(HBitOr node) => visitBinaryBitOp(node); |
(...skipping 11 matching lines...) Expand all Loading... |
286 visitFieldGet(HFieldGet node) => visitFieldAccess(node); | 286 visitFieldGet(HFieldGet node) => visitFieldAccess(node); |
287 visitFieldSet(HFieldSet node) => visitFieldAccess(node); | 287 visitFieldSet(HFieldSet node) => visitFieldAccess(node); |
288 visitForeign(HForeign node) => visitInstruction(node); | 288 visitForeign(HForeign node) => visitInstruction(node); |
289 visitForeignNew(HForeignNew node) => visitForeign(node); | 289 visitForeignNew(HForeignNew node) => visitForeign(node); |
290 visitGoto(HGoto node) => visitControlFlow(node); | 290 visitGoto(HGoto node) => visitControlFlow(node); |
291 visitGreater(HGreater node) => visitRelational(node); | 291 visitGreater(HGreater node) => visitRelational(node); |
292 visitGreaterEqual(HGreaterEqual node) => visitRelational(node); | 292 visitGreaterEqual(HGreaterEqual node) => visitRelational(node); |
293 visitIdentity(HIdentity node) => visitRelational(node); | 293 visitIdentity(HIdentity node) => visitRelational(node); |
294 visitIf(HIf node) => visitConditionalBranch(node); | 294 visitIf(HIf node) => visitConditionalBranch(node); |
295 visitIndex(HIndex node) => visitInstruction(node); | 295 visitIndex(HIndex node) => visitInstruction(node); |
296 visitIndexAssign(HIndexAssign node) => visitInvokeStatic(node); | 296 visitIndexAssign(HIndexAssign node) => visitInstruction(node); |
297 visitIntegerCheck(HIntegerCheck node) => visitCheck(node); | 297 visitIntegerCheck(HIntegerCheck node) => visitCheck(node); |
298 visitInterceptor(HInterceptor node) => visitInstruction(node); | 298 visitInterceptor(HInterceptor node) => visitInstruction(node); |
299 visitInvokeClosure(HInvokeClosure node) | 299 visitInvokeClosure(HInvokeClosure node) |
300 => visitInvokeDynamic(node); | 300 => visitInvokeDynamic(node); |
301 visitInvokeDynamicMethod(HInvokeDynamicMethod node) | 301 visitInvokeDynamicMethod(HInvokeDynamicMethod node) |
302 => visitInvokeDynamic(node); | 302 => visitInvokeDynamic(node); |
303 visitInvokeDynamicGetter(HInvokeDynamicGetter node) | 303 visitInvokeDynamicGetter(HInvokeDynamicGetter node) |
304 => visitInvokeDynamicField(node); | 304 => visitInvokeDynamicField(node); |
305 visitInvokeDynamicSetter(HInvokeDynamicSetter node) | 305 visitInvokeDynamicSetter(HInvokeDynamicSetter node) |
306 => visitInvokeDynamicField(node); | 306 => visitInvokeDynamicField(node); |
(...skipping 1015 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1322 | 1322 |
1323 class HInvokeDynamicMethod extends HInvokeDynamic { | 1323 class HInvokeDynamicMethod extends HInvokeDynamic { |
1324 HInvokeDynamicMethod(Selector selector, List<HInstruction> inputs) | 1324 HInvokeDynamicMethod(Selector selector, List<HInstruction> inputs) |
1325 : super(selector, null, inputs); | 1325 : super(selector, null, inputs); |
1326 String toString() => 'invoke dynamic method: $selector'; | 1326 String toString() => 'invoke dynamic method: $selector'; |
1327 accept(HVisitor visitor) => visitor.visitInvokeDynamicMethod(this); | 1327 accept(HVisitor visitor) => visitor.visitInvokeDynamicMethod(this); |
1328 | 1328 |
1329 bool isIndexOperatorOnIndexablePrimitive(HTypeMap types) { | 1329 bool isIndexOperatorOnIndexablePrimitive(HTypeMap types) { |
1330 return isInterceptorCall | 1330 return isInterceptorCall |
1331 && selector.kind == SelectorKind.INDEX | 1331 && selector.kind == SelectorKind.INDEX |
| 1332 && selector.name == const SourceString('[]') |
1332 && inputs[1].isIndexablePrimitive(types); | 1333 && inputs[1].isIndexablePrimitive(types); |
1333 } | 1334 } |
1334 | 1335 |
1335 HType computeDesiredTypeForInput(HInstruction input, | 1336 HType computeDesiredTypeForInput(HInstruction input, |
1336 HTypeMap types, | 1337 HTypeMap types, |
1337 Compiler compiler) { | 1338 Compiler compiler) { |
1338 // TODO(ngeoffray): Move this logic into a different class that | 1339 // TODO(ngeoffray): Move this logic into a different class that |
1339 // will know what type it wants for a given selector. | 1340 // will know what type it wants for a given selector. |
1340 if (selector.kind != SelectorKind.INDEX) return HType.UNKNOWN; | |
1341 if (!isInterceptorCall) return HType.UNKNOWN; | 1341 if (!isInterceptorCall) return HType.UNKNOWN; |
1342 | 1342 |
1343 HInstruction index = inputs[2]; | 1343 if (selector.kind == SelectorKind.INDEX) { |
1344 if (input == inputs[1] && | 1344 HInstruction index = inputs[2]; |
1345 (index.isTypeUnknown(types) || index.isNumber(types))) { | 1345 if (input == inputs[1] && |
1346 return HType.INDEXABLE_PRIMITIVE; | 1346 (index.isTypeUnknown(types) || index.isNumber(types))) { |
| 1347 return selector.name == const SourceString('[]') |
| 1348 ? HType.INDEXABLE_PRIMITIVE |
| 1349 : HType.MUTABLE_ARRAY; |
| 1350 } |
| 1351 // The index should be an int when the receiver is a string or array. |
| 1352 // However it turns out that inserting an integer check in the optimized |
| 1353 // version is cheaper than having another bailout case. This is true, |
| 1354 // because the integer check will simply throw if it fails. |
| 1355 return HType.UNKNOWN; |
| 1356 } else if (selector.kind == SelectorKind.OPERATOR) { |
| 1357 HType propagatedType = types[this]; |
| 1358 if (selector.name == const SourceString('-') && input == inputs[1]) { |
| 1359 // If the outgoing type should be a number (integer, double or both) we |
| 1360 // want the outgoing type to be the input too. |
| 1361 // If we don't know the outgoing type we try to make it a number. |
| 1362 if (propagatedType.isNumber()) return propagatedType; |
| 1363 if (propagatedType.isUnknown()) return HType.NUMBER; |
| 1364 } else if (selector.name == const SourceString('~') |
| 1365 && input == inputs[1]) { |
| 1366 if (propagatedType.isUnknown() || propagatedType.isNumber()) { |
| 1367 return HType.INTEGER; |
| 1368 } |
| 1369 } |
| 1370 return HType.UNKNOWN; |
1347 } | 1371 } |
1348 // The index should be an int when the receiver is a string or array. | 1372 return HType.UNKNOWN; |
1349 // However it turns out that inserting an integer check in the optimized | 1373 } |
1350 // version is cheaper than having another bailout case. This is true, | 1374 |
1351 // because the integer check will simply throw if it fails. | 1375 HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) { |
| 1376 // TODO(ngeoffray): Move this logic into a different class that |
| 1377 // will know what type it has for a given selector. |
| 1378 if (!isInterceptorCall) return HType.UNKNOWN; |
| 1379 |
| 1380 if (selector.kind == SelectorKind.OPERATOR) { |
| 1381 if (selector.name == const SourceString('-')) { |
| 1382 HType operandType = types[inputs[1]]; |
| 1383 if (operandType.isNumber()) return operandType; |
| 1384 } else if (selector.name == const SourceString('~')) { |
| 1385 // All bitwise operations on primitive types either produce an |
| 1386 // integer or throw an error. |
| 1387 if (inputs[1].isPrimitive(types)) return HType.INTEGER; |
| 1388 } |
| 1389 } |
1352 return HType.UNKNOWN; | 1390 return HType.UNKNOWN; |
1353 } | 1391 } |
1354 } | 1392 } |
1355 | 1393 |
1356 abstract class HInvokeDynamicField extends HInvokeDynamic { | 1394 abstract class HInvokeDynamicField extends HInvokeDynamic { |
1357 final bool isSideEffectFree; | 1395 final bool isSideEffectFree; |
1358 HInvokeDynamicField( | 1396 HInvokeDynamicField( |
1359 Selector selector, Element element, List<HInstruction> inputs, | 1397 Selector selector, Element element, List<HInstruction> inputs, |
1360 this.isSideEffectFree) | 1398 this.isSideEffectFree) |
1361 : super(selector, element, inputs); | 1399 : super(selector, element, inputs); |
(...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1833 : super(target, left, right); | 1871 : super(target, left, right); |
1834 accept(HVisitor visitor) => visitor.visitBitXor(this); | 1872 accept(HVisitor visitor) => visitor.visitBitXor(this); |
1835 | 1873 |
1836 BinaryOperation operation(ConstantSystem constantSystem) | 1874 BinaryOperation operation(ConstantSystem constantSystem) |
1837 => constantSystem.bitXor; | 1875 => constantSystem.bitXor; |
1838 int typeCode() => HInstruction.BIT_XOR_TYPECODE; | 1876 int typeCode() => HInstruction.BIT_XOR_TYPECODE; |
1839 bool typeEquals(other) => other is HBitXor; | 1877 bool typeEquals(other) => other is HBitXor; |
1840 bool dataEquals(HInstruction other) => true; | 1878 bool dataEquals(HInstruction other) => true; |
1841 } | 1879 } |
1842 | 1880 |
1843 abstract class HInvokeUnary extends HInvokeStatic { | 1881 abstract class HInvokeUnary extends HInstruction { |
1844 HInvokeUnary(HStatic target, HInstruction input) | 1882 HInvokeUnary(HInstruction input) : super(<HInstruction>[input]); |
1845 : super(<HInstruction>[target, input]); | |
1846 | 1883 |
1847 HInstruction get operand => inputs[1]; | 1884 HInstruction get operand => inputs[0]; |
1848 | 1885 |
1849 void prepareGvn(HTypeMap types) { | 1886 void prepareGvn(HTypeMap types) { |
1850 clearAllSideEffects(); | 1887 clearAllSideEffects(); |
1851 // A unary arithmetic expression can take part in global value | 1888 setUseGvn(); |
1852 // numbering and does not have any side-effects if its input is a | |
1853 // number. | |
1854 if (isBuiltin(types)) { | |
1855 setUseGvn(); | |
1856 } else { | |
1857 setAllSideEffects(); | |
1858 } | |
1859 } | 1889 } |
1860 | 1890 |
1861 bool isBuiltin(HTypeMap types) => operand.isNumber(types); | |
1862 | |
1863 HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) { | |
1864 HType operandType = types[operand]; | |
1865 if (operandType.isNumber()) return operandType; | |
1866 return HType.UNKNOWN; | |
1867 } | |
1868 | |
1869 HType computeDesiredTypeForNonTargetInput(HInstruction input, | |
1870 HTypeMap types, | |
1871 Compiler compiler) { | |
1872 HType propagatedType = types[this]; | |
1873 // If the outgoing type should be a number (integer, double or both) we | |
1874 // want the outgoing type to be the input too. | |
1875 // If we don't know the outgoing type we try to make it a number. | |
1876 if (propagatedType.isNumber()) return propagatedType; | |
1877 if (propagatedType.isUnknown()) return HType.NUMBER; | |
1878 return HType.UNKNOWN; | |
1879 } | |
1880 | |
1881 HType computeLikelyType(HTypeMap types, Compiler compiler) => HType.NUMBER; | |
1882 | |
1883 UnaryOperation operation(ConstantSystem constantSystem); | 1891 UnaryOperation operation(ConstantSystem constantSystem); |
1884 } | 1892 } |
1885 | 1893 |
1886 class HNegate extends HInvokeUnary { | 1894 class HNegate extends HInvokeUnary { |
1887 HNegate(HStatic target, HInstruction input) : super(target, input); | 1895 HNegate(HInstruction input) : super(input); |
1888 accept(HVisitor visitor) => visitor.visitNegate(this); | 1896 accept(HVisitor visitor) => visitor.visitNegate(this); |
1889 | 1897 |
| 1898 HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) { |
| 1899 return types[operand]; |
| 1900 } |
| 1901 |
1890 UnaryOperation operation(ConstantSystem constantSystem) | 1902 UnaryOperation operation(ConstantSystem constantSystem) |
1891 => constantSystem.negate; | 1903 => constantSystem.negate; |
1892 int typeCode() => HInstruction.NEGATE_TYPECODE; | 1904 int typeCode() => HInstruction.NEGATE_TYPECODE; |
1893 bool typeEquals(other) => other is HNegate; | 1905 bool typeEquals(other) => other is HNegate; |
1894 bool dataEquals(HInstruction other) => true; | 1906 bool dataEquals(HInstruction other) => true; |
1895 } | 1907 } |
1896 | 1908 |
1897 class HBitNot extends HInvokeUnary { | 1909 class HBitNot extends HInvokeUnary { |
1898 HBitNot(HStatic target, HInstruction input) : super(target, input); | 1910 HBitNot(HInstruction input) : super(input); |
1899 accept(HVisitor visitor) => visitor.visitBitNot(this); | 1911 accept(HVisitor visitor) => visitor.visitBitNot(this); |
1900 | 1912 |
1901 HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) { | 1913 HType get guaranteedType => HType.INTEGER; |
1902 // All bitwise operations on primitive types either produce an | |
1903 // integer or throw an error. | |
1904 if (operand.isPrimitive(types)) return HType.INTEGER; | |
1905 return HType.UNKNOWN; | |
1906 } | |
1907 | |
1908 HType computeDesiredTypeForNonTargetInput(HInstruction input, | |
1909 HTypeMap types, | |
1910 Compiler compiler) { | |
1911 HType propagatedType = types[this]; | |
1912 // Bit operations only work on integers. If there is no desired output | |
1913 // type or if it as a number we want to get an integer as input. | |
1914 if (propagatedType.isUnknown() || propagatedType.isNumber()) { | |
1915 return HType.INTEGER; | |
1916 } | |
1917 return HType.UNKNOWN; | |
1918 } | |
1919 | |
1920 UnaryOperation operation(ConstantSystem constantSystem) | 1914 UnaryOperation operation(ConstantSystem constantSystem) |
1921 => constantSystem.bitNot; | 1915 => constantSystem.bitNot; |
1922 int typeCode() => HInstruction.BIT_NOT_TYPECODE; | 1916 int typeCode() => HInstruction.BIT_NOT_TYPECODE; |
1923 bool typeEquals(other) => other is HBitNot; | 1917 bool typeEquals(other) => other is HBitNot; |
1924 bool dataEquals(HInstruction other) => true; | 1918 bool dataEquals(HInstruction other) => true; |
1925 } | 1919 } |
1926 | 1920 |
1927 class HExit extends HControlFlow { | 1921 class HExit extends HControlFlow { |
1928 HExit() : super(const <HInstruction>[]); | 1922 HExit() : super(const <HInstruction>[]); |
1929 toString() => 'exit'; | 1923 toString() => 'exit'; |
(...skipping 548 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2478 } | 2472 } |
2479 | 2473 |
2480 HInstruction get receiver => inputs[0]; | 2474 HInstruction get receiver => inputs[0]; |
2481 HInstruction get index => inputs[1]; | 2475 HInstruction get index => inputs[1]; |
2482 | 2476 |
2483 int typeCode() => HInstruction.INDEX_TYPECODE; | 2477 int typeCode() => HInstruction.INDEX_TYPECODE; |
2484 bool typeEquals(HInstruction other) => other is HIndex; | 2478 bool typeEquals(HInstruction other) => other is HIndex; |
2485 bool dataEquals(HIndex other) => true; | 2479 bool dataEquals(HIndex other) => true; |
2486 } | 2480 } |
2487 | 2481 |
2488 class HIndexAssign extends HInvokeStatic { | 2482 class HIndexAssign extends HInstruction { |
2489 HIndexAssign(HStatic target, | 2483 HIndexAssign(HInstruction receiver, |
2490 HInstruction receiver, | |
2491 HInstruction index, | 2484 HInstruction index, |
2492 HInstruction value) | 2485 HInstruction value) |
2493 : super(<HInstruction>[target, receiver, index, value]); | 2486 : super(<HInstruction>[receiver, index, value]); |
2494 toString() => 'index assign operator'; | 2487 String toString() => 'index assign operator'; |
2495 accept(HVisitor visitor) => visitor.visitIndexAssign(this); | 2488 accept(HVisitor visitor) => visitor.visitIndexAssign(this); |
2496 | 2489 |
2497 HInstruction get receiver => inputs[1]; | 2490 HInstruction get receiver => inputs[0]; |
2498 HInstruction get index => inputs[2]; | 2491 HInstruction get index => inputs[1]; |
2499 HInstruction get value => inputs[3]; | 2492 HInstruction get value => inputs[2]; |
2500 | 2493 |
2501 void prepareGvn(HTypeMap types) { | 2494 void prepareGvn(HTypeMap types) { |
2502 clearAllSideEffects(); | 2495 clearAllSideEffects(); |
2503 if (isBuiltin(types)) { | 2496 setChangesIndex(); |
2504 setChangesIndex(); | |
2505 } else { | |
2506 setAllSideEffects(); | |
2507 } | |
2508 } | 2497 } |
2509 | |
2510 // Note, that we don't have a computeTypeFromInputTypes, since [HIndexAssign] | |
2511 // is never used as input. | |
2512 | |
2513 HType computeDesiredTypeForNonTargetInput(HInstruction input, | |
2514 HTypeMap types, | |
2515 Compiler compiler) { | |
2516 if (input == receiver && | |
2517 (index.isTypeUnknown(types) || index.isNumber(types))) { | |
2518 return HType.MUTABLE_ARRAY; | |
2519 } | |
2520 // The index should be an int when the receiver is a string or array. | |
2521 // However it turns out that inserting an integer check in the optimized | |
2522 // version is cheaper than having another bailout case. This is true, | |
2523 // because the integer check will simply throw if it fails. | |
2524 return HType.UNKNOWN; | |
2525 } | |
2526 | |
2527 bool isBuiltin(HTypeMap types) | |
2528 => receiver.isMutableArray(types) && index.isInteger(types); | |
2529 bool isJsStatement(HTypeMap types) => !isBuiltin(types); | |
2530 } | 2498 } |
2531 | 2499 |
2532 class HIs extends HInstruction { | 2500 class HIs extends HInstruction { |
2533 final DartType typeExpression; | 2501 final DartType typeExpression; |
2534 final bool nullOk; | 2502 final bool nullOk; |
2535 | 2503 |
2536 HIs.withArgumentChecks(this.typeExpression, | 2504 HIs.withArgumentChecks(this.typeExpression, |
2537 HInstruction expression, | 2505 HInstruction expression, |
2538 List<HInstruction> checks, | 2506 List<HInstruction> checks, |
2539 [this.nullOk = false]) | 2507 [this.nullOk = false]) |
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2947 HBasicBlock get start => expression.start; | 2915 HBasicBlock get start => expression.start; |
2948 HBasicBlock get end { | 2916 HBasicBlock get end { |
2949 // We don't create a switch block if there are no cases. | 2917 // We don't create a switch block if there are no cases. |
2950 assert(!statements.isEmpty); | 2918 assert(!statements.isEmpty); |
2951 return statements.last.end; | 2919 return statements.last.end; |
2952 } | 2920 } |
2953 | 2921 |
2954 bool accept(HStatementInformationVisitor visitor) => | 2922 bool accept(HStatementInformationVisitor visitor) => |
2955 visitor.visitSwitchInfo(this); | 2923 visitor.visitSwitchInfo(this); |
2956 } | 2924 } |
OLD | NEW |