| 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 class SsaCodeGeneratorTask extends CompilerTask { | 5 class SsaCodeGeneratorTask extends CompilerTask { |
| 6 final JavaScriptBackend backend; | 6 final JavaScriptBackend backend; |
| 7 SsaCodeGeneratorTask(JavaScriptBackend backend) | 7 SsaCodeGeneratorTask(JavaScriptBackend backend) |
| 8 : this.backend = backend, | 8 : this.backend = backend, |
| 9 super(backend.compiler); | 9 super(backend.compiler); |
| 10 String get name() => 'SSA code generator'; | 10 String get name() => 'SSA code generator'; |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 176 | 176 |
| 177 // Records a block-information that is being handled specially. | 177 // Records a block-information that is being handled specially. |
| 178 // Used to break bad recursion. | 178 // Used to break bad recursion. |
| 179 HBlockInformation currentBlockInformation; | 179 HBlockInformation currentBlockInformation; |
| 180 // The subgraph is used to delimit traversal for some constructions, e.g., | 180 // The subgraph is used to delimit traversal for some constructions, e.g., |
| 181 // if branches. | 181 // if branches. |
| 182 SubGraph subGraph; | 182 SubGraph subGraph; |
| 183 | 183 |
| 184 LibraryElement get currentLibrary() => work.element.getLibrary(); | 184 LibraryElement get currentLibrary() => work.element.getLibrary(); |
| 185 Compiler get compiler() => backend.compiler; | 185 Compiler get compiler() => backend.compiler; |
| 186 Enqueuer get world() => backend.compiler.enqueuer.codegen; |
| 186 | 187 |
| 187 bool isGenerateAtUseSite(HInstruction instruction) { | 188 bool isGenerateAtUseSite(HInstruction instruction) { |
| 188 return generateAtUseSite.contains(instruction); | 189 return generateAtUseSite.contains(instruction); |
| 189 } | 190 } |
| 190 | 191 |
| 191 SsaCodeGenerator(this.backend, | 192 SsaCodeGenerator(this.backend, |
| 192 this.work, | 193 this.work, |
| 193 this.parameters, | 194 this.parameters, |
| 194 this.parameterNames) | 195 this.parameterNames) |
| 195 : names = new Map<int, String>(), | 196 : names = new Map<int, String>(), |
| (...skipping 1275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1471 // SsaBuilder.buildFactory. Is there a cleaner way to do this? | 1472 // SsaBuilder.buildFactory. Is there a cleaner way to do this? |
| 1472 node.name.printOn(buffer); | 1473 node.name.printOn(buffer); |
| 1473 visitArguments(node.inputs); | 1474 visitArguments(node.inputs); |
| 1474 } else { | 1475 } else { |
| 1475 buffer.add(compiler.namer.instanceMethodInvocationName( | 1476 buffer.add(compiler.namer.instanceMethodInvocationName( |
| 1476 currentLibrary, node.name, node.selector)); | 1477 currentLibrary, node.name, node.selector)); |
| 1477 visitArguments(node.inputs); | 1478 visitArguments(node.inputs); |
| 1478 if (node.element !== null) { | 1479 if (node.element !== null) { |
| 1479 // If we know we're calling a specific method, register that | 1480 // If we know we're calling a specific method, register that |
| 1480 // method only. | 1481 // method only. |
| 1481 compiler.registerDynamicInvocationOf(node.element); | 1482 world.registerDynamicInvocationOf(node.element); |
| 1482 } else { | 1483 } else { |
| 1483 compiler.registerDynamicInvocation( | 1484 world.registerDynamicInvocation( |
| 1484 node.name, getOptimizedSelectorFor(node, node.selector)); | 1485 node.name, getOptimizedSelectorFor(node, node.selector)); |
| 1485 } | 1486 } |
| 1486 } | 1487 } |
| 1487 endExpression(JSPrecedence.CALL_PRECEDENCE); | 1488 endExpression(JSPrecedence.CALL_PRECEDENCE); |
| 1488 } | 1489 } |
| 1489 | 1490 |
| 1490 Selector getOptimizedSelectorFor(HInvoke node, Selector defaultSelector) { | 1491 Selector getOptimizedSelectorFor(HInvoke node, Selector defaultSelector) { |
| 1491 Type receiverType = node.inputs[0].propagatedType.computeType(compiler); | 1492 Type receiverType = node.inputs[0].propagatedType.computeType(compiler); |
| 1492 if (receiverType !== null) { | 1493 if (receiverType !== null) { |
| 1493 return new TypedSelector(receiverType, defaultSelector); | 1494 return new TypedSelector(receiverType, defaultSelector); |
| 1494 } else { | 1495 } else { |
| 1495 return defaultSelector; | 1496 return defaultSelector; |
| 1496 } | 1497 } |
| 1497 } | 1498 } |
| 1498 | 1499 |
| 1499 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { | 1500 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
| 1500 beginExpression(JSPrecedence.CALL_PRECEDENCE); | 1501 beginExpression(JSPrecedence.CALL_PRECEDENCE); |
| 1501 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); | 1502 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); |
| 1502 buffer.add('.'); | 1503 buffer.add('.'); |
| 1503 buffer.add(compiler.namer.setterName(currentLibrary, node.name)); | 1504 buffer.add(compiler.namer.setterName(currentLibrary, node.name)); |
| 1504 visitArguments(node.inputs); | 1505 visitArguments(node.inputs); |
| 1505 compiler.registerDynamicSetter( | 1506 world.registerDynamicSetter( |
| 1506 node.name, getOptimizedSelectorFor(node, Selector.SETTER)); | 1507 node.name, getOptimizedSelectorFor(node, Selector.SETTER)); |
| 1507 endExpression(JSPrecedence.CALL_PRECEDENCE); | 1508 endExpression(JSPrecedence.CALL_PRECEDENCE); |
| 1508 } | 1509 } |
| 1509 | 1510 |
| 1510 visitInvokeDynamicGetter(HInvokeDynamicGetter node) { | 1511 visitInvokeDynamicGetter(HInvokeDynamicGetter node) { |
| 1511 beginExpression(JSPrecedence.CALL_PRECEDENCE); | 1512 beginExpression(JSPrecedence.CALL_PRECEDENCE); |
| 1512 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); | 1513 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); |
| 1513 buffer.add('.'); | 1514 buffer.add('.'); |
| 1514 buffer.add(compiler.namer.getterName(currentLibrary, node.name)); | 1515 buffer.add(compiler.namer.getterName(currentLibrary, node.name)); |
| 1515 visitArguments(node.inputs); | 1516 visitArguments(node.inputs); |
| 1516 compiler.registerDynamicGetter( | 1517 world.registerDynamicGetter( |
| 1517 node.name, getOptimizedSelectorFor(node, Selector.GETTER)); | 1518 node.name, getOptimizedSelectorFor(node, Selector.GETTER)); |
| 1518 endExpression(JSPrecedence.CALL_PRECEDENCE); | 1519 endExpression(JSPrecedence.CALL_PRECEDENCE); |
| 1519 } | 1520 } |
| 1520 | 1521 |
| 1521 visitInvokeClosure(HInvokeClosure node) { | 1522 visitInvokeClosure(HInvokeClosure node) { |
| 1522 beginExpression(JSPrecedence.CALL_PRECEDENCE); | 1523 beginExpression(JSPrecedence.CALL_PRECEDENCE); |
| 1523 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); | 1524 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); |
| 1524 buffer.add('.'); | 1525 buffer.add('.'); |
| 1525 buffer.add(compiler.namer.closureInvocationName(node.selector)); | 1526 buffer.add(compiler.namer.closureInvocationName(node.selector)); |
| 1526 visitArguments(node.inputs); | 1527 visitArguments(node.inputs); |
| 1527 // TODO(floitsch): we should have a separate list for closure invocations. | 1528 // TODO(floitsch): we should have a separate list for closure invocations. |
| 1528 compiler.registerDynamicInvocation(Namer.CLOSURE_INVOCATION_NAME, | 1529 world.registerDynamicInvocation(Namer.CLOSURE_INVOCATION_NAME, |
| 1529 node.selector); | 1530 node.selector); |
| 1530 endExpression(JSPrecedence.CALL_PRECEDENCE); | 1531 endExpression(JSPrecedence.CALL_PRECEDENCE); |
| 1531 } | 1532 } |
| 1532 | 1533 |
| 1533 visitInvokeStatic(HInvokeStatic node) { | 1534 visitInvokeStatic(HInvokeStatic node) { |
| 1534 beginExpression(JSPrecedence.CALL_PRECEDENCE); | 1535 beginExpression(JSPrecedence.CALL_PRECEDENCE); |
| 1535 use(node.target, JSPrecedence.CALL_PRECEDENCE); | 1536 use(node.target, JSPrecedence.CALL_PRECEDENCE); |
| 1536 visitArguments(node.inputs); | 1537 visitArguments(node.inputs); |
| 1537 endExpression(JSPrecedence.CALL_PRECEDENCE); | 1538 endExpression(JSPrecedence.CALL_PRECEDENCE); |
| 1538 } | 1539 } |
| 1539 | 1540 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1552 visitArguments(node.inputs); | 1553 visitArguments(node.inputs); |
| 1553 } else if (superMethod.kind == ElementKind.FIELD) { | 1554 } else if (superMethod.kind == ElementKind.FIELD) { |
| 1554 buffer.add('this.${compiler.namer.getName(superMethod)}'); | 1555 buffer.add('this.${compiler.namer.getName(superMethod)}'); |
| 1555 } else { | 1556 } else { |
| 1556 assert(superMethod.kind == ElementKind.GETTER); | 1557 assert(superMethod.kind == ElementKind.GETTER); |
| 1557 String methodName = | 1558 String methodName = |
| 1558 compiler.namer.getterName(currentLibrary, superMethod.name); | 1559 compiler.namer.getterName(currentLibrary, superMethod.name); |
| 1559 buffer.add('$className.prototype.$methodName.call()'); | 1560 buffer.add('$className.prototype.$methodName.call()'); |
| 1560 } | 1561 } |
| 1561 endExpression(JSPrecedence.CALL_PRECEDENCE); | 1562 endExpression(JSPrecedence.CALL_PRECEDENCE); |
| 1562 compiler.registerStaticUse(superMethod); | 1563 world.registerStaticUse(superMethod); |
| 1563 } | 1564 } |
| 1564 | 1565 |
| 1565 visitFieldGet(HFieldGet node) { | 1566 visitFieldGet(HFieldGet node) { |
| 1566 if (node.receiver !== null) { | 1567 if (node.receiver !== null) { |
| 1567 String name = | 1568 String name = |
| 1568 compiler.namer.instanceFieldName(currentLibrary, node.name); | 1569 compiler.namer.instanceFieldName(currentLibrary, node.name); |
| 1569 beginExpression(JSPrecedence.MEMBER_PRECEDENCE); | 1570 beginExpression(JSPrecedence.MEMBER_PRECEDENCE); |
| 1570 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); | 1571 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); |
| 1571 buffer.add('.'); | 1572 buffer.add('.'); |
| 1572 buffer.add(name); | 1573 buffer.add(name); |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1806 use(node.value, JSPrecedence.EQUALITY_PRECEDENCE); | 1807 use(node.value, JSPrecedence.EQUALITY_PRECEDENCE); |
| 1807 buffer.add(' !== ('); | 1808 buffer.add(' !== ('); |
| 1808 use(node.value, JSPrecedence.BITWISE_OR_PRECEDENCE); | 1809 use(node.value, JSPrecedence.BITWISE_OR_PRECEDENCE); |
| 1809 buffer.add(" | 0)) "); | 1810 buffer.add(" | 0)) "); |
| 1810 } | 1811 } |
| 1811 generateThrowWithHelper('iae', node.value); | 1812 generateThrowWithHelper('iae', node.value); |
| 1812 } | 1813 } |
| 1813 | 1814 |
| 1814 void generateThrowWithHelper(String helperName, HInstruction argument) { | 1815 void generateThrowWithHelper(String helperName, HInstruction argument) { |
| 1815 Element helper = compiler.findHelper(new SourceString(helperName)); | 1816 Element helper = compiler.findHelper(new SourceString(helperName)); |
| 1816 compiler.registerStaticUse(helper); | 1817 world.registerStaticUse(helper); |
| 1817 buffer.add('throw '); | 1818 buffer.add('throw '); |
| 1818 beginExpression(JSPrecedence.EXPRESSION_PRECEDENCE); | 1819 beginExpression(JSPrecedence.EXPRESSION_PRECEDENCE); |
| 1819 beginExpression(JSPrecedence.CALL_PRECEDENCE); | 1820 beginExpression(JSPrecedence.CALL_PRECEDENCE); |
| 1820 buffer.add(compiler.namer.isolateAccess(helper)); | 1821 buffer.add(compiler.namer.isolateAccess(helper)); |
| 1821 visitArguments([null, argument]); | 1822 visitArguments([null, argument]); |
| 1822 endExpression(JSPrecedence.CALL_PRECEDENCE); | 1823 endExpression(JSPrecedence.CALL_PRECEDENCE); |
| 1823 endExpression(JSPrecedence.EXPRESSION_PRECEDENCE); | 1824 endExpression(JSPrecedence.EXPRESSION_PRECEDENCE); |
| 1824 } | 1825 } |
| 1825 | 1826 |
| 1826 void addIndentation() { | 1827 void addIndentation() { |
| 1827 for (int i = 0; i < indent; i++) { | 1828 for (int i = 0; i < indent; i++) { |
| 1828 buffer.add(' '); | 1829 buffer.add(' '); |
| 1829 } | 1830 } |
| 1830 } | 1831 } |
| 1831 | 1832 |
| 1832 void addIndented(String text) { | 1833 void addIndented(String text) { |
| 1833 addIndentation(); | 1834 addIndentation(); |
| 1834 buffer.add(text); | 1835 buffer.add(text); |
| 1835 } | 1836 } |
| 1836 | 1837 |
| 1837 void visitStatic(HStatic node) { | 1838 void visitStatic(HStatic node) { |
| 1838 compiler.registerStaticUse(node.element); | 1839 world.registerStaticUse(node.element); |
| 1839 buffer.add(compiler.namer.isolateAccess(node.element)); | 1840 buffer.add(compiler.namer.isolateAccess(node.element)); |
| 1840 } | 1841 } |
| 1841 | 1842 |
| 1842 void visitStaticStore(HStaticStore node) { | 1843 void visitStaticStore(HStaticStore node) { |
| 1843 compiler.registerStaticUse(node.element); | 1844 world.registerStaticUse(node.element); |
| 1844 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); | 1845 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 1845 buffer.add(compiler.namer.isolateAccess(node.element)); | 1846 buffer.add(compiler.namer.isolateAccess(node.element)); |
| 1846 buffer.add(' = '); | 1847 buffer.add(' = '); |
| 1847 use(node.inputs[0], JSPrecedence.ASSIGNMENT_PRECEDENCE); | 1848 use(node.inputs[0], JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 1848 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); | 1849 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 1849 } | 1850 } |
| 1850 | 1851 |
| 1851 void visitLiteralList(HLiteralList node) { | 1852 void visitLiteralList(HLiteralList node) { |
| 1852 generateArrayLiteral(node); | 1853 generateArrayLiteral(node); |
| 1853 } | 1854 } |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2096 } | 2097 } |
| 2097 | 2098 |
| 2098 void visitIs(HIs node) { | 2099 void visitIs(HIs node) { |
| 2099 Type type = node.typeExpression; | 2100 Type type = node.typeExpression; |
| 2100 Element element = type.element; | 2101 Element element = type.element; |
| 2101 if (element.kind === ElementKind.TYPE_VARIABLE) { | 2102 if (element.kind === ElementKind.TYPE_VARIABLE) { |
| 2102 compiler.unimplemented("visitIs for type variables", instruction: node); | 2103 compiler.unimplemented("visitIs for type variables", instruction: node); |
| 2103 } else if (element.kind === ElementKind.TYPEDEF) { | 2104 } else if (element.kind === ElementKind.TYPEDEF) { |
| 2104 compiler.unimplemented("visitIs for typedefs", instruction: node); | 2105 compiler.unimplemented("visitIs for typedefs", instruction: node); |
| 2105 } | 2106 } |
| 2106 compiler.registerIsCheck(type.element); | 2107 world.registerIsCheck(type.element); |
| 2107 LibraryElement coreLibrary = compiler.coreLibrary; | 2108 LibraryElement coreLibrary = compiler.coreLibrary; |
| 2108 ClassElement objectClass = compiler.objectClass; | 2109 ClassElement objectClass = compiler.objectClass; |
| 2109 HInstruction input = node.expression; | 2110 HInstruction input = node.expression; |
| 2110 | 2111 |
| 2111 if (node.nullOk) { | 2112 if (node.nullOk) { |
| 2112 beginExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); | 2113 beginExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); |
| 2113 checkNull(input); | 2114 checkNull(input); |
| 2114 buffer.add(' || '); | 2115 buffer.add(' || '); |
| 2115 } | 2116 } |
| 2116 if (element === objectClass || element === compiler.dynamicClass) { | 2117 if (element === objectClass || element === compiler.dynamicClass) { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2163 }); | 2164 }); |
| 2164 } | 2165 } |
| 2165 if (node.nullOk) { | 2166 if (node.nullOk) { |
| 2166 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); | 2167 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); |
| 2167 } | 2168 } |
| 2168 } | 2169 } |
| 2169 | 2170 |
| 2170 void visitTypeConversion(HTypeConversion node) { | 2171 void visitTypeConversion(HTypeConversion node) { |
| 2171 if (node.checked) { | 2172 if (node.checked) { |
| 2172 Element element = node.type.computeType(compiler).element; | 2173 Element element = node.type.computeType(compiler).element; |
| 2173 compiler.registerIsCheck(element); | 2174 world.registerIsCheck(element); |
| 2174 SourceString helper; | 2175 SourceString helper; |
| 2175 String additionalArgument; | 2176 String additionalArgument; |
| 2176 bool nativeCheck = | 2177 bool nativeCheck = |
| 2177 backend.emitter.nativeEmitter.requiresNativeIsCheck(element); | 2178 backend.emitter.nativeEmitter.requiresNativeIsCheck(element); |
| 2178 beginExpression(JSPrecedence.CALL_PRECEDENCE); | 2179 beginExpression(JSPrecedence.CALL_PRECEDENCE); |
| 2179 | 2180 |
| 2180 if (element == compiler.stringClass) { | 2181 if (element == compiler.stringClass) { |
| 2181 helper = const SourceString('stringTypeCheck'); | 2182 helper = const SourceString('stringTypeCheck'); |
| 2182 } else if (element == compiler.doubleClass) { | 2183 } else if (element == compiler.doubleClass) { |
| 2183 helper = const SourceString('doubleTypeCheck'); | 2184 helper = const SourceString('doubleTypeCheck'); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2205 } else { | 2206 } else { |
| 2206 helper = const SourceString('listSuperTypeCheck'); | 2207 helper = const SourceString('listSuperTypeCheck'); |
| 2207 } | 2208 } |
| 2208 } else if (nativeCheck) { | 2209 } else if (nativeCheck) { |
| 2209 helper = const SourceString('callTypeCheck'); | 2210 helper = const SourceString('callTypeCheck'); |
| 2210 } else { | 2211 } else { |
| 2211 helper = const SourceString('propertyTypeCheck'); | 2212 helper = const SourceString('propertyTypeCheck'); |
| 2212 } | 2213 } |
| 2213 } | 2214 } |
| 2214 Element helperElement = compiler.findHelper(helper); | 2215 Element helperElement = compiler.findHelper(helper); |
| 2215 compiler.registerStaticUse(helperElement); | 2216 world.registerStaticUse(helperElement); |
| 2216 buffer.add(compiler.namer.isolateAccess(helperElement)); | 2217 buffer.add(compiler.namer.isolateAccess(helperElement)); |
| 2217 buffer.add('('); | 2218 buffer.add('('); |
| 2218 use(node.checkedInput, JSPrecedence.EXPRESSION_PRECEDENCE); | 2219 use(node.checkedInput, JSPrecedence.EXPRESSION_PRECEDENCE); |
| 2219 if (additionalArgument !== null) buffer.add(", '$additionalArgument'"); | 2220 if (additionalArgument !== null) buffer.add(", '$additionalArgument'"); |
| 2220 buffer.add(')'); | 2221 buffer.add(')'); |
| 2221 endExpression(JSPrecedence.CALL_PRECEDENCE); | 2222 endExpression(JSPrecedence.CALL_PRECEDENCE); |
| 2222 } else { | 2223 } else { |
| 2223 use(node.checkedInput, expectedPrecedence); | 2224 use(node.checkedInput, expectedPrecedence); |
| 2224 } | 2225 } |
| 2225 } | 2226 } |
| (...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2621 startBailoutSwitch(); | 2622 startBailoutSwitch(); |
| 2622 } | 2623 } |
| 2623 } | 2624 } |
| 2624 | 2625 |
| 2625 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2626 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2626 if (labeledBlockInfo.body.start.hasGuards()) { | 2627 if (labeledBlockInfo.body.start.hasGuards()) { |
| 2627 endBailoutSwitch(); | 2628 endBailoutSwitch(); |
| 2628 } | 2629 } |
| 2629 } | 2630 } |
| 2630 } | 2631 } |
| OLD | NEW |