OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library dart2js.cps_ir.type_propagation; | 4 library dart2js.cps_ir.type_propagation; |
5 | 5 |
6 import 'optimizers.dart'; | 6 import 'optimizers.dart'; |
7 | 7 |
8 import '../closure.dart' show | 8 import '../closure.dart' show |
9 ClosureClassElement, Identifiers; | 9 ClosureClassElement, Identifiers; |
10 import '../common/names.dart' show | 10 import '../common/names.dart' show |
(...skipping 960 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
971 if (!node.selector.isCall || | 971 if (!node.selector.isCall || |
972 node.selector.positionalArgumentCount != 1 || | 972 node.selector.positionalArgumentCount != 1 || |
973 node.selector.namedArgumentCount != 0) { | 973 node.selector.namedArgumentCount != 0) { |
974 return false; | 974 return false; |
975 } | 975 } |
976 if (!isExtendable) return false; | 976 if (!isExtendable) return false; |
977 Primitive addedItem = getDartArgument(node, 0); | 977 Primitive addedItem = getDartArgument(node, 0); |
978 CpsFragment cps = new CpsFragment(sourceInfo); | 978 CpsFragment cps = new CpsFragment(sourceInfo); |
979 cps.invokeBuiltin(BuiltinMethod.Push, | 979 cps.invokeBuiltin(BuiltinMethod.Push, |
980 list, | 980 list, |
981 <Primitive>[addedItem], | 981 <Primitive>[addedItem]); |
982 receiverIsNotNull: listValue.isDefinitelyNotNull); | |
983 cps.invokeContinuation(cont, [cps.makeNull()]); | 982 cps.invokeContinuation(cont, [cps.makeNull()]); |
984 replaceSubtree(node, cps.result); | 983 replaceSubtree(node, cps.result); |
985 push(cps.result); | 984 push(cps.result); |
986 return true; | 985 return true; |
987 | 986 |
988 case 'removeLast': | 987 case 'removeLast': |
989 if (!node.selector.isCall || | 988 if (!node.selector.isCall || |
990 node.selector.argumentCount != 0) { | 989 node.selector.argumentCount != 0) { |
991 return false; | 990 return false; |
992 } | 991 } |
993 if (!isExtendable) return false; | 992 if (!isExtendable) return false; |
994 CpsFragment cps = new CpsFragment(sourceInfo); | 993 CpsFragment cps = new CpsFragment(sourceInfo); |
995 Primitive length = cps.letPrim(new GetLength(list)); | 994 Primitive length = cps.letPrim(new GetLength(list)); |
996 Primitive isEmpty = cps.applyBuiltin( | 995 Primitive isEmpty = cps.applyBuiltin( |
997 BuiltinOperator.StrictEq, | 996 BuiltinOperator.StrictEq, |
998 [length, cps.makeZero()]); | 997 [length, cps.makeZero()]); |
999 CpsFragment fail = cps.ifTruthy(isEmpty); | 998 CpsFragment fail = cps.ifTruthy(isEmpty); |
1000 fail.invokeStaticThrower( | 999 fail.invokeStaticThrower( |
1001 backend.getThrowIndexOutOfBoundsError(), | 1000 backend.getThrowIndexOutOfBoundsError(), |
1002 [list, fail.makeConstant(new IntConstantValue(-1))]); | 1001 [list, fail.makeConstant(new IntConstantValue(-1))]); |
1003 Primitive removedItem = cps.invokeBuiltin(BuiltinMethod.Pop, | 1002 Primitive removedItem = cps.invokeBuiltin(BuiltinMethod.Pop, |
1004 list, | 1003 list, |
1005 <Primitive>[], | 1004 <Primitive>[]); |
1006 receiverIsNotNull: listValue.isDefinitelyNotNull); | |
1007 cps.invokeContinuation(cont, [removedItem]); | 1005 cps.invokeContinuation(cont, [removedItem]); |
1008 replaceSubtree(node, cps.result); | 1006 replaceSubtree(node, cps.result); |
1009 push(cps.result); | 1007 push(cps.result); |
1010 return true; | 1008 return true; |
1011 | 1009 |
1012 case 'addAll': | 1010 case 'addAll': |
1013 if (!node.selector.isCall || | 1011 if (!node.selector.isCall || |
1014 node.selector.argumentCount != 1) { | 1012 node.selector.argumentCount != 1) { |
1015 return false; | 1013 return false; |
1016 } | 1014 } |
1017 if (!isExtendable) return false; | 1015 if (!isExtendable) return false; |
1018 Primitive addedList = getDartArgument(node, 0); | 1016 Primitive addedList = getDartArgument(node, 0); |
1019 // Rewrite addAll([x1, ..., xN]) to push(x1, ..., xN). | 1017 // Rewrite addAll([x1, ..., xN]) to push(x1, ..., xN). |
1020 // Ensure that the list is not mutated between creation and use. | 1018 // Ensure that the list is not mutated between creation and use. |
1021 // We aim for the common case where this is the only use of the list, | 1019 // We aim for the common case where this is the only use of the list, |
1022 // which also guarantees that this list is not mutated before use. | 1020 // which also guarantees that this list is not mutated before use. |
1023 if (addedList is! LiteralList || !addedList.hasExactlyOneUse) { | 1021 if (addedList is! LiteralList || !addedList.hasExactlyOneUse) { |
1024 return false; | 1022 return false; |
1025 } | 1023 } |
1026 LiteralList addedLiteral = addedList; | 1024 LiteralList addedLiteral = addedList; |
1027 CpsFragment cps = new CpsFragment(sourceInfo); | 1025 CpsFragment cps = new CpsFragment(sourceInfo); |
1028 cps.invokeBuiltin(BuiltinMethod.Push, | 1026 cps.invokeBuiltin(BuiltinMethod.Push, |
1029 list, | 1027 list, |
1030 addedLiteral.values.map((ref) => ref.definition).toList(), | 1028 addedLiteral.values.map((ref) => ref.definition).toList()); |
1031 receiverIsNotNull: listValue.isDefinitelyNotNull); | |
1032 cps.invokeContinuation(cont, [cps.makeNull()]); | 1029 cps.invokeContinuation(cont, [cps.makeNull()]); |
1033 replaceSubtree(node, cps.result); | 1030 replaceSubtree(node, cps.result); |
1034 push(cps.result); | 1031 push(cps.result); |
1035 return true; | 1032 return true; |
1036 | 1033 |
1037 case 'elementAt': | 1034 case 'elementAt': |
1038 if (!node.selector.isCall || | 1035 if (!node.selector.isCall || |
1039 node.selector.positionalArgumentCount != 1 || | 1036 node.selector.positionalArgumentCount != 1 || |
1040 node.selector.namedArgumentCount != 0) { | 1037 node.selector.namedArgumentCount != 0) { |
1041 return false; | 1038 return false; |
(...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1469 void visitInvokeMethod(InvokeMethod node) { | 1466 void visitInvokeMethod(InvokeMethod node) { |
1470 if (constifyExpression(node)) return; | 1467 if (constifyExpression(node)) return; |
1471 if (specializeOperatorCall(node)) return; | 1468 if (specializeOperatorCall(node)) return; |
1472 if (specializeFieldAccess(node)) return; | 1469 if (specializeFieldAccess(node)) return; |
1473 if (specializeIndexableAccess(node)) return; | 1470 if (specializeIndexableAccess(node)) return; |
1474 if (specializeArrayAccess(node)) return; | 1471 if (specializeArrayAccess(node)) return; |
1475 if (specializeSingleUseClosureCall(node)) return; | 1472 if (specializeSingleUseClosureCall(node)) return; |
1476 if (specializeClosureCall(node)) return; | 1473 if (specializeClosureCall(node)) return; |
1477 | 1474 |
1478 AbstractValue receiver = getValue(node.receiver.definition); | 1475 AbstractValue receiver = getValue(node.receiver.definition); |
1479 node.receiverIsNotNull = receiver.isDefinitelyNotNull; | |
1480 | 1476 |
1481 if (node.receiverIsIntercepted && | 1477 if (node.receiverIsIntercepted && |
1482 node.receiver.definition.sameValue(node.arguments[0].definition)) { | 1478 node.receiver.definition.sameValue(node.arguments[0].definition)) { |
1483 // The receiver and first argument are the same; that means we already | 1479 // The receiver and first argument are the same; that means we already |
1484 // determined in visitInterceptor that we are targeting a non-interceptor. | 1480 // determined in visitInterceptor that we are targeting a non-interceptor. |
1485 | 1481 |
1486 // Check if any of the possible targets depend on the extra receiver | 1482 // Check if any of the possible targets depend on the extra receiver |
1487 // argument. Mixins do this, and tear-offs always needs the extra receiver | 1483 // argument. Mixins do this, and tear-offs always needs the extra receiver |
1488 // argument because BoundClosure uses it for equality and hash code. | 1484 // argument because BoundClosure uses it for equality and hash code. |
1489 // TODO(15933): Make automatically generated property extraction | 1485 // TODO(15933): Make automatically generated property extraction |
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1826 if (node.dartType == dartTypes.coreTypes.numType || | 1822 if (node.dartType == dartTypes.coreTypes.numType || |
1827 node.dartType == dartTypes.coreTypes.doubleType) { | 1823 node.dartType == dartTypes.coreTypes.doubleType) { |
1828 return new ApplyBuiltinOperator( | 1824 return new ApplyBuiltinOperator( |
1829 BuiltinOperator.IsNumber, | 1825 BuiltinOperator.IsNumber, |
1830 <Primitive>[prim], | 1826 <Primitive>[prim], |
1831 node.sourceInformation); | 1827 node.sourceInformation); |
1832 } | 1828 } |
1833 return null; | 1829 return null; |
1834 } | 1830 } |
1835 | 1831 |
1836 void visitGetField(GetField node) { | |
1837 node.objectIsNotNull = getValue(node.object.definition).isDefinitelyNotNull; | |
1838 } | |
1839 | |
1840 void visitGetLength(GetLength node) { | |
1841 node.objectIsNotNull = getValue(node.object.definition).isDefinitelyNotNull; | |
1842 } | |
1843 | |
1844 Primitive visitInterceptor(Interceptor node) { | 1832 Primitive visitInterceptor(Interceptor node) { |
1845 AbstractValue value = getValue(node.input.definition); | 1833 AbstractValue value = getValue(node.input.definition); |
1846 // If the exact class of the input is known, replace with a constant | 1834 // If the exact class of the input is known, replace with a constant |
1847 // or the input itself. | 1835 // or the input itself. |
1848 ClassElement singleClass; | 1836 ClassElement singleClass; |
1849 if (lattice.isDefinitelyInt(value)) { | 1837 if (lattice.isDefinitelyInt(value)) { |
1850 // Classes like JSUInt31 and JSUInt32 do not exist at runtime, so ensure | 1838 // Classes like JSUInt31 and JSUInt32 do not exist at runtime, so ensure |
1851 // all the int classes get mapped tor their runtime class. | 1839 // all the int classes get mapped tor their runtime class. |
1852 singleClass = backend.jsIntClass; | 1840 singleClass = backend.jsIntClass; |
1853 } else if (lattice.isDefinitelyNativeList(value)) { | 1841 } else if (lattice.isDefinitelyNativeList(value)) { |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2132 // continuation. Note that this is effectively a phi node in SSA terms. | 2120 // continuation. Note that this is effectively a phi node in SSA terms. |
2133 for (int i = 0; i < node.arguments.length; i++) { | 2121 for (int i = 0; i < node.arguments.length; i++) { |
2134 Primitive def = node.arguments[i].definition; | 2122 Primitive def = node.arguments[i].definition; |
2135 AbstractValue cell = getValue(def); | 2123 AbstractValue cell = getValue(def); |
2136 setValue(cont.parameters[i], cell); | 2124 setValue(cont.parameters[i], cell); |
2137 } | 2125 } |
2138 } | 2126 } |
2139 | 2127 |
2140 void visitInvokeMethod(InvokeMethod node) { | 2128 void visitInvokeMethod(InvokeMethod node) { |
2141 AbstractValue receiver = getValue(node.receiver.definition); | 2129 AbstractValue receiver = getValue(node.receiver.definition); |
| 2130 node.receiverIsNotNull = receiver.isDefinitelyNotNull; |
2142 if (receiver.isNothing) { | 2131 if (receiver.isNothing) { |
2143 return; // And come back later. | 2132 return; // And come back later. |
2144 } | 2133 } |
2145 if (!node.selector.isOperator) { | 2134 if (!node.selector.isOperator) { |
2146 // TODO(jgruber): Handle known methods on constants such as String.length. | 2135 // TODO(jgruber): Handle known methods on constants such as String.length. |
2147 setResult(node, lattice.getInvokeReturnType(node.selector, node.mask)); | 2136 setResult(node, lattice.getInvokeReturnType(node.selector, node.mask)); |
2148 return; | 2137 return; |
2149 } | 2138 } |
2150 | 2139 |
2151 // Calculate the resulting constant if possible. | 2140 // Calculate the resulting constant if possible. |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2436 // null gets returned. | 2425 // null gets returned. |
2437 // TODO(asgerf): Add the NullInterceptor when it enables us to | 2426 // TODO(asgerf): Add the NullInterceptor when it enables us to |
2438 // propagate an assignment. | 2427 // propagate an assignment. |
2439 setValue(node, nonConstant()); | 2428 setValue(node, nonConstant()); |
2440 } else { | 2429 } else { |
2441 setValue(node, nonConstant(typeSystem.nonNullType)); | 2430 setValue(node, nonConstant(typeSystem.nonNullType)); |
2442 } | 2431 } |
2443 } | 2432 } |
2444 | 2433 |
2445 void visitGetField(GetField node) { | 2434 void visitGetField(GetField node) { |
| 2435 node.objectIsNotNull = getValue(node.object.definition).isDefinitelyNotNull; |
2446 setValue(node, nonConstant(typeSystem.getFieldType(node.field))); | 2436 setValue(node, nonConstant(typeSystem.getFieldType(node.field))); |
2447 } | 2437 } |
2448 | 2438 |
2449 void visitSetField(SetField node) {} | 2439 void visitSetField(SetField node) {} |
2450 | 2440 |
2451 void visitCreateBox(CreateBox node) { | 2441 void visitCreateBox(CreateBox node) { |
2452 setValue(node, nonConstant(typeSystem.nonNullType)); | 2442 setValue(node, nonConstant(typeSystem.nonNullType)); |
2453 } | 2443 } |
2454 | 2444 |
2455 void visitCreateInstance(CreateInstance node) { | 2445 void visitCreateInstance(CreateInstance node) { |
(...skipping 25 matching lines...) Expand all Loading... |
2481 @override | 2471 @override |
2482 void visitForeignCode(ForeignCode node) { | 2472 void visitForeignCode(ForeignCode node) { |
2483 if (node.continuation != null) { | 2473 if (node.continuation != null) { |
2484 setResult(node, nonConstant(node.type)); | 2474 setResult(node, nonConstant(node.type)); |
2485 } | 2475 } |
2486 } | 2476 } |
2487 | 2477 |
2488 @override | 2478 @override |
2489 void visitGetLength(GetLength node) { | 2479 void visitGetLength(GetLength node) { |
2490 AbstractValue input = getValue(node.object.definition); | 2480 AbstractValue input = getValue(node.object.definition); |
| 2481 node.objectIsNotNull = getValue(node.object.definition).isDefinitelyNotNull; |
2491 int length = typeSystem.getContainerLength(input.type); | 2482 int length = typeSystem.getContainerLength(input.type); |
2492 if (length != null) { | 2483 if (length != null) { |
2493 // TODO(asgerf): Constant-folding the length might degrade the VM's | 2484 // TODO(asgerf): Constant-folding the length might degrade the VM's |
2494 // own bounds-check elimination? | 2485 // own bounds-check elimination? |
2495 setValue(node, constantValue(new IntConstantValue(length))); | 2486 setValue(node, constantValue(new IntConstantValue(length))); |
2496 } else { | 2487 } else { |
2497 setValue(node, nonConstant(typeSystem.intType)); | 2488 setValue(node, nonConstant(typeSystem.intType)); |
2498 } | 2489 } |
2499 } | 2490 } |
2500 | 2491 |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2641 processLetPrim(LetPrim node) { | 2632 processLetPrim(LetPrim node) { |
2642 node.primitive.type = null; | 2633 node.primitive.type = null; |
2643 values[node.primitive] = null; | 2634 values[node.primitive] = null; |
2644 } | 2635 } |
2645 | 2636 |
2646 processLetMutable(LetMutable node) { | 2637 processLetMutable(LetMutable node) { |
2647 node.variable.type = null; | 2638 node.variable.type = null; |
2648 values[node.variable] = null; | 2639 values[node.variable] = null; |
2649 } | 2640 } |
2650 } | 2641 } |
OLD | NEW |