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 class SsaCodeGeneratorTask extends CompilerTask { | 7 class SsaCodeGeneratorTask extends CompilerTask { |
8 | 8 |
9 final JavaScriptBackend backend; | 9 final JavaScriptBackend backend; |
10 final SourceInformationStrategy sourceInformationFactory; | 10 final SourceInformationStrategy sourceInformationFactory; |
(...skipping 1561 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1572 .withSourceInformation(node.sourceInformation)); | 1572 .withSourceInformation(node.sourceInformation)); |
1573 } | 1573 } |
1574 | 1574 |
1575 void visitInvokeConstructorBody(HInvokeConstructorBody node) { | 1575 void visitInvokeConstructorBody(HInvokeConstructorBody node) { |
1576 use(node.inputs[0]); | 1576 use(node.inputs[0]); |
1577 js.Expression object = pop(); | 1577 js.Expression object = pop(); |
1578 js.Name methodName = backend.namer.instanceMethodName(node.element); | 1578 js.Name methodName = backend.namer.instanceMethodName(node.element); |
1579 List<js.Expression> arguments = visitArguments(node.inputs); | 1579 List<js.Expression> arguments = visitArguments(node.inputs); |
1580 push(js.propertyCall(object, methodName, arguments) | 1580 push(js.propertyCall(object, methodName, arguments) |
1581 .withSourceInformation(node.sourceInformation)); | 1581 .withSourceInformation(node.sourceInformation)); |
1582 registry.registerStaticUse(node.element); | 1582 registry.registerStaticUse( |
| 1583 new StaticUse.constructorBodyInvoke( |
| 1584 node.element, new CallStructure.unnamed(arguments.length))); |
1583 } | 1585 } |
1584 | 1586 |
1585 void visitOneShotInterceptor(HOneShotInterceptor node) { | 1587 void visitOneShotInterceptor(HOneShotInterceptor node) { |
1586 List<js.Expression> arguments = visitArguments(node.inputs); | 1588 List<js.Expression> arguments = visitArguments(node.inputs); |
1587 var isolate = new js.VariableUse( | 1589 var isolate = new js.VariableUse( |
1588 backend.namer.globalObjectFor(helpers.interceptorsLibrary)); | 1590 backend.namer.globalObjectFor(helpers.interceptorsLibrary)); |
1589 Selector selector = node.selector; | 1591 Selector selector = node.selector; |
1590 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); | 1592 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); |
1591 js.Name methodName = backend.registerOneShotInterceptor(selector); | 1593 js.Name methodName = backend.registerOneShotInterceptor(selector); |
1592 push(js.propertyCall(isolate, methodName, arguments) | 1594 push(js.propertyCall(isolate, methodName, arguments) |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1634 | 1636 |
1635 // If we don't know what we're calling or if we are calling a getter, | 1637 // If we don't know what we're calling or if we are calling a getter, |
1636 // we need to register that fact that we may be calling a closure | 1638 // we need to register that fact that we may be calling a closure |
1637 // with the same arguments. | 1639 // with the same arguments. |
1638 Element target = node.element; | 1640 Element target = node.element; |
1639 if (target == null || target.isGetter) { | 1641 if (target == null || target.isGetter) { |
1640 // TODO(kasperl): If we have a typed selector for the call, we | 1642 // TODO(kasperl): If we have a typed selector for the call, we |
1641 // may know something about the types of closures that need | 1643 // may know something about the types of closures that need |
1642 // the specific closure call method. | 1644 // the specific closure call method. |
1643 Selector call = new Selector.callClosureFrom(selector); | 1645 Selector call = new Selector.callClosureFrom(selector); |
1644 registry.registerDynamicInvocation( | 1646 registry.registerDynamicUse( |
1645 new UniverseSelector(call, null)); | 1647 new UniverseSelector(call, null)); |
1646 } | 1648 } |
1647 registry.registerDynamicInvocation( | 1649 registry.registerDynamicUse( |
1648 new UniverseSelector(selector, mask)); | 1650 new UniverseSelector(selector, mask)); |
1649 } | 1651 } |
1650 | 1652 |
1651 void registerSetter(HInvokeDynamic node) { | 1653 void registerSetter(HInvokeDynamic node) { |
1652 Selector selector = node.selector; | 1654 Selector selector = node.selector; |
1653 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); | 1655 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); |
1654 registry.registerDynamicSetter( | 1656 registry.registerDynamicUse( |
1655 new UniverseSelector(selector, mask)); | 1657 new UniverseSelector(selector, mask)); |
1656 } | 1658 } |
1657 | 1659 |
1658 void registerGetter(HInvokeDynamic node) { | 1660 void registerGetter(HInvokeDynamic node) { |
1659 Selector selector = node.selector; | 1661 Selector selector = node.selector; |
1660 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); | 1662 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); |
1661 registry.registerDynamicGetter( | 1663 registry.registerDynamicUse( |
1662 new UniverseSelector(selector, mask)); | 1664 new UniverseSelector(selector, mask)); |
1663 } | 1665 } |
1664 | 1666 |
1665 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { | 1667 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
1666 use(node.receiver); | 1668 use(node.receiver); |
1667 js.Name name = backend.namer.invocationName(node.selector); | 1669 js.Name name = backend.namer.invocationName(node.selector); |
1668 push(js.propertyCall(pop(), name, visitArguments(node.inputs)) | 1670 push(js.propertyCall(pop(), name, visitArguments(node.inputs)) |
1669 .withSourceInformation(node.sourceInformation)); | 1671 .withSourceInformation(node.sourceInformation)); |
1670 registerSetter(node); | 1672 registerSetter(node); |
1671 } | 1673 } |
1672 | 1674 |
1673 visitInvokeDynamicGetter(HInvokeDynamicGetter node) { | 1675 visitInvokeDynamicGetter(HInvokeDynamicGetter node) { |
1674 use(node.receiver); | 1676 use(node.receiver); |
1675 js.Name name = backend.namer.invocationName(node.selector); | 1677 js.Name name = backend.namer.invocationName(node.selector); |
1676 push(js.propertyCall(pop(), name, visitArguments(node.inputs)) | 1678 push(js.propertyCall(pop(), name, visitArguments(node.inputs)) |
1677 .withSourceInformation(node.sourceInformation)); | 1679 .withSourceInformation(node.sourceInformation)); |
1678 registerGetter(node); | 1680 registerGetter(node); |
1679 } | 1681 } |
1680 | 1682 |
1681 visitInvokeClosure(HInvokeClosure node) { | 1683 visitInvokeClosure(HInvokeClosure node) { |
1682 Selector call = new Selector.callClosureFrom(node.selector); | 1684 Selector call = new Selector.callClosureFrom(node.selector); |
1683 use(node.receiver); | 1685 use(node.receiver); |
1684 push(js.propertyCall(pop(), | 1686 push(js.propertyCall(pop(), |
1685 backend.namer.invocationName(call), | 1687 backend.namer.invocationName(call), |
1686 visitArguments(node.inputs)) | 1688 visitArguments(node.inputs)) |
1687 .withSourceInformation(node.sourceInformation)); | 1689 .withSourceInformation(node.sourceInformation)); |
1688 registry.registerDynamicInvocation( | 1690 registry.registerDynamicUse( |
1689 new UniverseSelector(call, null)); | 1691 new UniverseSelector(call, null)); |
1690 } | 1692 } |
1691 | 1693 |
1692 visitInvokeStatic(HInvokeStatic node) { | 1694 visitInvokeStatic(HInvokeStatic node) { |
1693 Element element = node.element; | 1695 Element element = node.element; |
1694 List<DartType> instantiatedTypes = node.instantiatedTypes; | 1696 List<DartType> instantiatedTypes = node.instantiatedTypes; |
1695 | 1697 |
1696 if (instantiatedTypes != null && !instantiatedTypes.isEmpty) { | 1698 if (instantiatedTypes != null && !instantiatedTypes.isEmpty) { |
1697 instantiatedTypes.forEach((type) { | 1699 instantiatedTypes.forEach((type) { |
1698 registry.registerInstantiatedType(type); | 1700 registry.registerInstantiation(type); |
1699 }); | 1701 }); |
1700 } | 1702 } |
1701 | 1703 |
1702 List<js.Expression> arguments = visitArguments(node.inputs, start: 0); | 1704 List<js.Expression> arguments = visitArguments(node.inputs, start: 0); |
1703 | 1705 |
1704 if (element == backend.helpers.checkConcurrentModificationError) { | 1706 if (element == backend.helpers.checkConcurrentModificationError) { |
1705 // Manually inline the [checkConcurrentModificationError] function. This | 1707 // Manually inline the [checkConcurrentModificationError] function. This |
1706 // function is only called from a for-loop update. Ideally we would just | 1708 // function is only called from a for-loop update. Ideally we would just |
1707 // generate the conditionalcontrol flow in the builder but it adds basic | 1709 // generate the conditionalcontrol flow in the builder but it adds basic |
1708 // blocks in the loop update that interfere with other optimizations and | 1710 // blocks in the loop update that interfere with other optimizations and |
1709 // confuses loop recognition. | 1711 // confuses loop recognition. |
1710 | 1712 |
1711 assert(arguments.length == 2); | 1713 assert(arguments.length == 2); |
1712 Element throwFunction = backend.helpers.throwConcurrentModificationError; | 1714 Element throwFunction = backend.helpers.throwConcurrentModificationError; |
1713 registry.registerStaticInvocation(throwFunction); | 1715 registry.registerStaticUse( |
| 1716 new StaticUse.staticInvoke(throwFunction, CallStructure.ONE_ARG)); |
1714 | 1717 |
1715 // Calling using `(0, #)(#)` instead of `#(#)` separates the property load | 1718 // Calling using `(0, #)(#)` instead of `#(#)` separates the property load |
1716 // of the static function access from the call. For some reason this | 1719 // of the static function access from the call. For some reason this |
1717 // helps V8 see that the call never happens so V8 makes the call a | 1720 // helps V8 see that the call never happens so V8 makes the call a |
1718 // deoptimization. This removes the call from the optimized loop, making | 1721 // deoptimization. This removes the call from the optimized loop, making |
1719 // more optimizations available to the loop. This form is 50% faster on | 1722 // more optimizations available to the loop. This form is 50% faster on |
1720 // some small loop, almost as fast as loops with no concurrent | 1723 // some small loop, almost as fast as loops with no concurrent |
1721 // modification check. | 1724 // modification check. |
1722 push(js.js('# || (0, #)(#)',[ | 1725 push(js.js('# || (0, #)(#)',[ |
1723 arguments[0], | 1726 arguments[0], |
1724 backend.emitter.staticFunctionAccess(throwFunction), | 1727 backend.emitter.staticFunctionAccess(throwFunction), |
1725 arguments[1]])); | 1728 arguments[1]])); |
1726 } else { | 1729 } else { |
1727 registry.registerStaticInvocation(element); | 1730 CallStructure callStructure = new CallStructure.unnamed(arguments.length); |
| 1731 registry.registerStaticUse( |
| 1732 element.isConstructor |
| 1733 ? new StaticUse.constructorInvoke(element, callStructure) |
| 1734 : new StaticUse.staticInvoke(element, callStructure)); |
1728 push(backend.emitter.staticFunctionAccess(element)); | 1735 push(backend.emitter.staticFunctionAccess(element)); |
1729 push(new js.Call(pop(), arguments, | 1736 push(new js.Call(pop(), arguments, |
1730 sourceInformation: node.sourceInformation)); | 1737 sourceInformation: node.sourceInformation)); |
1731 } | 1738 } |
1732 | 1739 |
1733 } | 1740 } |
1734 | 1741 |
1735 visitInvokeSuper(HInvokeSuper node) { | 1742 visitInvokeSuper(HInvokeSuper node) { |
1736 Element superMethod = node.element; | 1743 Element superElement = node.element; |
1737 registry.registerSuperInvocation(superMethod); | 1744 ClassElement superClass = superElement.enclosingClass; |
1738 ClassElement superClass = superMethod.enclosingClass; | 1745 if (superElement.isField) { |
1739 if (superMethod.kind == ElementKind.FIELD) { | |
1740 js.Name fieldName = | 1746 js.Name fieldName = |
1741 backend.namer.instanceFieldPropertyName(superMethod); | 1747 backend.namer.instanceFieldPropertyName(superElement); |
1742 use(node.inputs[0]); | 1748 use(node.inputs[0]); |
1743 js.PropertyAccess access = | 1749 js.PropertyAccess access = |
1744 new js.PropertyAccess(pop(), fieldName) | 1750 new js.PropertyAccess(pop(), fieldName) |
1745 .withSourceInformation(node.sourceInformation); | 1751 .withSourceInformation(node.sourceInformation); |
1746 if (node.isSetter) { | 1752 if (node.isSetter) { |
| 1753 registry.registerStaticUse( |
| 1754 new StaticUse.superSet(superElement)); |
1747 use(node.value); | 1755 use(node.value); |
1748 push(new js.Assignment(access, pop()) | 1756 push(new js.Assignment(access, pop()) |
1749 .withSourceInformation(node.sourceInformation)); | 1757 .withSourceInformation(node.sourceInformation)); |
1750 } else { | 1758 } else { |
| 1759 registry.registerStaticUse(new StaticUse.superGet(superElement)); |
1751 push(access); | 1760 push(access); |
1752 } | 1761 } |
1753 } else { | 1762 } else { |
1754 Selector selector = node.selector; | 1763 Selector selector = node.selector; |
1755 | 1764 if (!backend.maybeRegisterAliasedSuperMember(superElement, selector)) { |
1756 if (!backend.maybeRegisterAliasedSuperMember(superMethod, selector)) { | |
1757 js.Name methodName; | 1765 js.Name methodName; |
1758 if (selector.isGetter) { | 1766 if (selector.isGetter) { |
1759 // If the selector we need to register a typed getter to the | 1767 // If the selector we need to register a typed getter to the |
1760 // [world]. The emitter needs to know if it needs to emit a | 1768 // [world]. The emitter needs to know if it needs to emit a |
1761 // bound closure for a method. | 1769 // bound closure for a method. |
1762 | 1770 |
1763 // If [superMethod] is mixed in, [superClass] might not be live. | 1771 // If [superMethod] is mixed in, [superClass] might not be live. |
1764 // We use the superclass of the access instead. | 1772 // We use the superclass of the access instead. |
1765 TypeMask receiverType = | 1773 TypeMask receiverType = |
1766 new TypeMask.nonNullExact(node.caller.superclass, compiler.world); | 1774 new TypeMask.nonNullExact(node.caller.superclass, compiler.world); |
1767 // TODO(floitsch): we know the target. We shouldn't register a | 1775 // TODO(floitsch): we know the target. We shouldn't register a |
1768 // dynamic getter. | 1776 // dynamic getter. |
1769 registry.registerDynamicGetter( | 1777 registry.registerDynamicUse( |
1770 new UniverseSelector(selector, receiverType)); | 1778 new UniverseSelector(selector, receiverType)); |
1771 registry.registerGetterForSuperMethod(node.element); | 1779 if (superElement.isFunction) { |
| 1780 registry.registerStaticUse( |
| 1781 new StaticUse.superTearOff(superElement)); |
| 1782 } |
1772 methodName = backend.namer.invocationName(selector); | 1783 methodName = backend.namer.invocationName(selector); |
1773 } else { | 1784 } else { |
1774 assert(invariant(node, compiler.hasIncrementalSupport)); | 1785 assert(invariant(node, compiler.hasIncrementalSupport)); |
1775 methodName = backend.namer.instanceMethodName(superMethod); | 1786 methodName = backend.namer.instanceMethodName(superElement); |
1776 } | 1787 } |
| 1788 registry.registerStaticUse( |
| 1789 new StaticUse.superInvoke( |
| 1790 superElement, |
| 1791 new CallStructure.unnamed(node.inputs.length))); |
1777 push(js.js('#.#.call(#)', | 1792 push(js.js('#.#.call(#)', |
1778 [backend.emitter.prototypeAccess(superClass, | 1793 [backend.emitter.prototypeAccess(superClass, |
1779 hasBeenInstantiated: true), | 1794 hasBeenInstantiated: true), |
1780 methodName, visitArguments(node.inputs, start: 0)]) | 1795 methodName, visitArguments(node.inputs, start: 0)]) |
1781 .withSourceInformation(node.sourceInformation)); | 1796 .withSourceInformation(node.sourceInformation)); |
1782 } else { | 1797 } else { |
1783 use(node.receiver); | 1798 use(node.receiver); |
| 1799 registry.registerStaticUse( |
| 1800 new StaticUse.superInvoke( |
| 1801 superElement, |
| 1802 new CallStructure.unnamed(node.inputs.length - 1))); |
1784 push( | 1803 push( |
1785 js.js('#.#(#)', [ | 1804 js.js('#.#(#)', [ |
1786 pop(), backend.namer.aliasedSuperMemberPropertyName(superMethod), | 1805 pop(), backend.namer.aliasedSuperMemberPropertyName(superElement), |
1787 visitArguments(node.inputs, start: 1)]) // Skip receiver argument. | 1806 visitArguments(node.inputs, start: 1)]) // Skip receiver argument. |
1788 .withSourceInformation(node.sourceInformation)); | 1807 .withSourceInformation(node.sourceInformation)); |
1789 } | 1808 } |
1790 } | 1809 } |
1791 } | 1810 } |
1792 | 1811 |
1793 visitFieldGet(HFieldGet node) { | 1812 visitFieldGet(HFieldGet node) { |
1794 use(node.receiver); | 1813 use(node.receiver); |
1795 Element element = node.element; | 1814 Element element = node.element; |
1796 if (node.isNullCheck) { | 1815 if (node.isNullCheck) { |
1797 // We access a JavaScript member we know all objects besides | 1816 // We access a JavaScript member we know all objects besides |
1798 // null and undefined have: V8 does not like accessing a member | 1817 // null and undefined have: V8 does not like accessing a member |
1799 // that does not exist. | 1818 // that does not exist. |
1800 push(new js.PropertyAccess.field(pop(), 'toString') | 1819 push(new js.PropertyAccess.field(pop(), 'toString') |
1801 .withSourceInformation(node.sourceInformation)); | 1820 .withSourceInformation(node.sourceInformation)); |
1802 } else if (element == helpers.jsIndexableLength) { | 1821 } else if (element == helpers.jsIndexableLength) { |
1803 // We're accessing a native JavaScript property called 'length' | 1822 // We're accessing a native JavaScript property called 'length' |
1804 // on a JS String or a JS array. Therefore, the name of that | 1823 // on a JS String or a JS array. Therefore, the name of that |
1805 // property should not be mangled. | 1824 // property should not be mangled. |
1806 push(new js.PropertyAccess.field(pop(), 'length') | 1825 push(new js.PropertyAccess.field(pop(), 'length') |
1807 .withSourceInformation(node.sourceInformation)); | 1826 .withSourceInformation(node.sourceInformation)); |
1808 } else { | 1827 } else { |
1809 js.Name name = backend.namer.instanceFieldPropertyName(element); | 1828 js.Name name = backend.namer.instanceFieldPropertyName(element); |
1810 push(new js.PropertyAccess(pop(), name) | 1829 push(new js.PropertyAccess(pop(), name) |
1811 .withSourceInformation(node.sourceInformation)); | 1830 .withSourceInformation(node.sourceInformation)); |
1812 registry.registerFieldGetter(element); | 1831 registry.registerStaticUse(new StaticUse.fieldGet(element)); |
1813 } | 1832 } |
1814 } | 1833 } |
1815 | 1834 |
1816 visitFieldSet(HFieldSet node) { | 1835 visitFieldSet(HFieldSet node) { |
1817 Element element = node.element; | 1836 Element element = node.element; |
1818 registry.registerFieldSetter(element); | 1837 registry.registerStaticUse(new StaticUse.fieldSet(element)); |
1819 js.Name name = backend.namer.instanceFieldPropertyName(element); | 1838 js.Name name = backend.namer.instanceFieldPropertyName(element); |
1820 use(node.receiver); | 1839 use(node.receiver); |
1821 js.Expression receiver = pop(); | 1840 js.Expression receiver = pop(); |
1822 use(node.value); | 1841 use(node.value); |
1823 push(new js.Assignment(new js.PropertyAccess(receiver, name), pop()) | 1842 push(new js.Assignment(new js.PropertyAccess(receiver, name), pop()) |
1824 .withSourceInformation(node.sourceInformation)); | 1843 .withSourceInformation(node.sourceInformation)); |
1825 } | 1844 } |
1826 | 1845 |
1827 visitReadModifyWrite(HReadModifyWrite node) { | 1846 visitReadModifyWrite(HReadModifyWrite node) { |
1828 Element element = node.element; | 1847 Element element = node.element; |
1829 registry.registerFieldSetter(element); | 1848 registry.registerStaticUse(new StaticUse.fieldGet(element)); |
| 1849 registry.registerStaticUse(new StaticUse.fieldSet(element)); |
1830 js.Name name = backend.namer.instanceFieldPropertyName(element); | 1850 js.Name name = backend.namer.instanceFieldPropertyName(element); |
1831 use(node.receiver); | 1851 use(node.receiver); |
1832 js.Expression fieldReference = new js.PropertyAccess(pop(), name); | 1852 js.Expression fieldReference = new js.PropertyAccess(pop(), name); |
1833 if (node.isPreOp) { | 1853 if (node.isPreOp) { |
1834 push(new js.Prefix(node.jsOp, fieldReference) | 1854 push(new js.Prefix(node.jsOp, fieldReference) |
1835 .withSourceInformation(node.sourceInformation)); | 1855 .withSourceInformation(node.sourceInformation)); |
1836 } else if (node.isPostOp) { | 1856 } else if (node.isPostOp) { |
1837 push(new js.Postfix(node.jsOp, fieldReference) | 1857 push(new js.Postfix(node.jsOp, fieldReference) |
1838 .withSourceInformation(node.sourceInformation)); | 1858 .withSourceInformation(node.sourceInformation)); |
1839 } else { | 1859 } else { |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1894 // We also use ForeignNew to instantiate closure classes that belong to | 1914 // We also use ForeignNew to instantiate closure classes that belong to |
1895 // function expressions. We have to register their use here, as otherwise | 1915 // function expressions. We have to register their use here, as otherwise |
1896 // code for them might not be emitted. | 1916 // code for them might not be emitted. |
1897 if (node.element.isClosure) { | 1917 if (node.element.isClosure) { |
1898 registry.registerInstantiatedClass(node.element); | 1918 registry.registerInstantiatedClass(node.element); |
1899 } | 1919 } |
1900 if (node.instantiatedTypes == null) { | 1920 if (node.instantiatedTypes == null) { |
1901 return; | 1921 return; |
1902 } | 1922 } |
1903 node.instantiatedTypes.forEach((type) { | 1923 node.instantiatedTypes.forEach((type) { |
1904 registry.registerInstantiatedType(type); | 1924 registry.registerInstantiation(type); |
1905 }); | 1925 }); |
1906 } | 1926 } |
1907 | 1927 |
1908 js.Expression newLiteralBool(bool value, | 1928 js.Expression newLiteralBool(bool value, |
1909 SourceInformation sourceInformation) { | 1929 SourceInformation sourceInformation) { |
1910 if (compiler.enableMinification) { | 1930 if (compiler.enableMinification) { |
1911 // Use !0 for true, !1 for false. | 1931 // Use !0 for true, !1 for false. |
1912 return new js.Prefix("!", new js.LiteralNumber(value ? "0" : "1")) | 1932 return new js.Prefix("!", new js.LiteralNumber(value ? "0" : "1")) |
1913 .withSourceInformation(sourceInformation); | 1933 .withSourceInformation(sourceInformation); |
1914 } else { | 1934 } else { |
1915 return new js.LiteralBool(value) | 1935 return new js.LiteralBool(value) |
1916 .withSourceInformation(sourceInformation); | 1936 .withSourceInformation(sourceInformation); |
1917 } | 1937 } |
1918 } | 1938 } |
1919 | 1939 |
1920 void generateConstant(ConstantValue constant, | 1940 void generateConstant(ConstantValue constant, |
1921 SourceInformation sourceInformation) { | 1941 SourceInformation sourceInformation) { |
1922 if (constant.isFunction) { | 1942 if (constant.isFunction) { |
1923 FunctionConstantValue function = constant; | 1943 FunctionConstantValue function = constant; |
1924 registry.registerStaticUse(function.element); | 1944 registry.registerStaticUse( |
| 1945 new StaticUse.staticTearOff(function.element)); |
1925 } | 1946 } |
1926 if (constant.isType) { | 1947 if (constant.isType) { |
1927 // If the type is a web component, we need to ensure the constructors are | 1948 // If the type is a web component, we need to ensure the constructors are |
1928 // available to 'upgrade' the native object. | 1949 // available to 'upgrade' the native object. |
1929 TypeConstantValue type = constant; | 1950 TypeConstantValue type = constant; |
1930 Element element = type.representedType.element; | 1951 Element element = type.representedType.element; |
1931 if (element != null && element.isClass) { | 1952 if (element != null && element.isClass) { |
1932 registry.registerTypeConstant(element); | 1953 registry.registerTypeConstant(element); |
1933 } | 1954 } |
1934 } | 1955 } |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2150 pushStatement(new js.If.noElse(underOver, thenBody) | 2171 pushStatement(new js.If.noElse(underOver, thenBody) |
2151 .withSourceInformation(node.sourceInformation)); | 2172 .withSourceInformation(node.sourceInformation)); |
2152 } else { | 2173 } else { |
2153 generateThrowWithHelper(helpers.throwIndexOutOfRangeException, | 2174 generateThrowWithHelper(helpers.throwIndexOutOfRangeException, |
2154 [node.array, node.index]); | 2175 [node.array, node.index]); |
2155 } | 2176 } |
2156 } | 2177 } |
2157 | 2178 |
2158 void generateThrowWithHelper(Element helper, argument, | 2179 void generateThrowWithHelper(Element helper, argument, |
2159 {SourceInformation sourceInformation}) { | 2180 {SourceInformation sourceInformation}) { |
2160 registry.registerStaticUse(helper); | |
2161 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); | 2181 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); |
2162 List arguments = []; | 2182 List arguments = []; |
2163 var location; | 2183 var location; |
2164 if (argument is List) { | 2184 if (argument is List) { |
2165 location = argument[0]; | 2185 location = argument[0]; |
2166 argument.forEach((instruction) { | 2186 argument.forEach((instruction) { |
2167 use(instruction); | 2187 use(instruction); |
2168 arguments.add(pop()); | 2188 arguments.add(pop()); |
2169 }); | 2189 }); |
2170 } else { | 2190 } else { |
2171 location = argument; | 2191 location = argument; |
2172 use(argument); | 2192 use(argument); |
2173 arguments.add(pop()); | 2193 arguments.add(pop()); |
2174 } | 2194 } |
| 2195 registry.registerStaticUse( |
| 2196 new StaticUse.staticInvoke( |
| 2197 helper, new CallStructure.unnamed(arguments.length))); |
2175 js.Call value = new js.Call(jsHelper, arguments.toList(growable: false), | 2198 js.Call value = new js.Call(jsHelper, arguments.toList(growable: false), |
2176 sourceInformation: sourceInformation); | 2199 sourceInformation: sourceInformation); |
2177 // BUG(4906): Using throw/return here adds to the size of the generated code | 2200 // BUG(4906): Using throw/return here adds to the size of the generated code |
2178 // but it has the advantage of explicitly telling the JS engine that | 2201 // but it has the advantage of explicitly telling the JS engine that |
2179 // this code path will terminate abruptly. Needs more work. | 2202 // this code path will terminate abruptly. Needs more work. |
2180 if (helper == helpers.wrapExceptionHelper) { | 2203 if (helper == helpers.wrapExceptionHelper) { |
2181 pushStatement(new js.Throw(value) | 2204 pushStatement(new js.Throw(value) |
2182 .withSourceInformation(sourceInformation)); | 2205 .withSourceInformation(sourceInformation)); |
2183 } else { | 2206 } else { |
2184 Element element = work.element; | 2207 Element element = work.element; |
2185 if (element is FunctionElement && element.asyncMarker.isYielding) { | 2208 if (element is FunctionElement && element.asyncMarker.isYielding) { |
2186 // `return <expr>;` is illegal in a sync* or async* function. | 2209 // `return <expr>;` is illegal in a sync* or async* function. |
2187 // To have the the async-translator working, we avoid introducing | 2210 // To have the the async-translator working, we avoid introducing |
2188 // `return` nodes. | 2211 // `return` nodes. |
2189 pushStatement(new js.ExpressionStatement(value) | 2212 pushStatement(new js.ExpressionStatement(value) |
2190 .withSourceInformation(sourceInformation)); | 2213 .withSourceInformation(sourceInformation)); |
2191 } else { | 2214 } else { |
2192 pushStatement(new js.Return(value) | 2215 pushStatement(new js.Return(value) |
2193 .withSourceInformation(sourceInformation)); | 2216 .withSourceInformation(sourceInformation)); |
2194 } | 2217 } |
2195 } | 2218 } |
2196 } | 2219 } |
2197 | 2220 |
2198 visitThrowExpression(HThrowExpression node) { | 2221 visitThrowExpression(HThrowExpression node) { |
2199 HInstruction argument = node.inputs[0]; | 2222 HInstruction argument = node.inputs[0]; |
2200 use(argument); | 2223 use(argument); |
2201 | 2224 |
2202 Element helper = helpers.throwExpressionHelper; | 2225 Element helper = helpers.throwExpressionHelper; |
2203 registry.registerStaticUse(helper); | 2226 registry.registerStaticUse( |
| 2227 new StaticUse.staticInvoke(helper, CallStructure.ONE_ARG)); |
2204 | 2228 |
2205 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); | 2229 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); |
2206 js.Call value = new js.Call(jsHelper, [pop()]) | 2230 js.Call value = new js.Call(jsHelper, [pop()]) |
2207 .withSourceInformation(node.sourceInformation); | 2231 .withSourceInformation(node.sourceInformation); |
2208 push(value); | 2232 push(value); |
2209 } | 2233 } |
2210 | 2234 |
2211 void visitSwitch(HSwitch node) { | 2235 void visitSwitch(HSwitch node) { |
2212 // Switches are handled using [visitSwitchInfo]. | 2236 // Switches are handled using [visitSwitchInfo]. |
2213 } | 2237 } |
2214 | 2238 |
2215 void visitStatic(HStatic node) { | 2239 void visitStatic(HStatic node) { |
2216 Element element = node.element; | 2240 Element element = node.element; |
2217 assert(element.isFunction || element.isField); | 2241 assert(element.isFunction || element.isField); |
2218 if (element.isFunction) { | 2242 if (element.isFunction) { |
2219 push(backend.emitter.isolateStaticClosureAccess(element) | 2243 push(backend.emitter.isolateStaticClosureAccess(element) |
2220 .withSourceInformation(node.sourceInformation)); | 2244 .withSourceInformation(node.sourceInformation)); |
2221 registry.registerGetOfStaticFunction(element); | 2245 registry.registerStaticUse( |
| 2246 new StaticUse.staticTearOff(element)); |
2222 } else { | 2247 } else { |
2223 push(backend.emitter.staticFieldAccess(element) | 2248 push(backend.emitter.staticFieldAccess(element) |
2224 .withSourceInformation(node.sourceInformation)); | 2249 .withSourceInformation(node.sourceInformation)); |
| 2250 registry.registerStaticUse( |
| 2251 new StaticUse.staticGet(element)); |
2225 } | 2252 } |
2226 registry.registerStaticUse(element); | |
2227 } | 2253 } |
2228 | 2254 |
2229 void visitLazyStatic(HLazyStatic node) { | 2255 void visitLazyStatic(HLazyStatic node) { |
2230 Element element = node.element; | 2256 Element element = node.element; |
2231 registry.registerStaticUse(element); | 2257 registry.registerStaticUse( |
| 2258 new StaticUse.staticInit(element)); |
2232 js.Expression lazyGetter = | 2259 js.Expression lazyGetter = |
2233 backend.emitter.isolateLazyInitializerAccess(element); | 2260 backend.emitter.isolateLazyInitializerAccess(element); |
2234 js.Call call = new js.Call(lazyGetter, <js.Expression>[], | 2261 js.Call call = new js.Call(lazyGetter, <js.Expression>[], |
2235 sourceInformation: node.sourceInformation); | 2262 sourceInformation: node.sourceInformation); |
2236 push(call); | 2263 push(call); |
2237 } | 2264 } |
2238 | 2265 |
2239 void visitStaticStore(HStaticStore node) { | 2266 void visitStaticStore(HStaticStore node) { |
2240 registry.registerStaticUse(node.element); | 2267 registry.registerStaticUse( |
| 2268 new StaticUse.staticSet(node.element)); |
2241 js.Node variable = backend.emitter.staticFieldAccess(node.element); | 2269 js.Node variable = backend.emitter.staticFieldAccess(node.element); |
2242 use(node.inputs[0]); | 2270 use(node.inputs[0]); |
2243 push(new js.Assignment(variable, pop()) | 2271 push(new js.Assignment(variable, pop()) |
2244 .withSourceInformation(node.sourceInformation)); | 2272 .withSourceInformation(node.sourceInformation)); |
2245 } | 2273 } |
2246 | 2274 |
2247 void visitStringConcat(HStringConcat node) { | 2275 void visitStringConcat(HStringConcat node) { |
2248 use(node.left); | 2276 use(node.left); |
2249 js.Expression jsLeft = pop(); | 2277 js.Expression jsLeft = pop(); |
2250 use(node.right); | 2278 use(node.right); |
(...skipping 13 matching lines...) Expand all Loading... |
2264 && node.usedBy[0] is HStringConcat | 2292 && node.usedBy[0] is HStringConcat |
2265 && node.usedBy[0].inputs[1] == node) { | 2293 && node.usedBy[0].inputs[1] == node) { |
2266 // The context is already <string> + value. | 2294 // The context is already <string> + value. |
2267 } else { | 2295 } else { |
2268 // Force an empty string for the first operand. | 2296 // Force an empty string for the first operand. |
2269 push(new js.Binary('+', js.string(""), pop()) | 2297 push(new js.Binary('+', js.string(""), pop()) |
2270 .withSourceInformation(node.sourceInformation)); | 2298 .withSourceInformation(node.sourceInformation)); |
2271 } | 2299 } |
2272 } else { | 2300 } else { |
2273 Element convertToString = backend.helpers.stringInterpolationHelper; | 2301 Element convertToString = backend.helpers.stringInterpolationHelper; |
2274 registry.registerStaticUse(convertToString); | 2302 registry.registerStaticUse( |
| 2303 new StaticUse.staticInvoke(convertToString, CallStructure.ONE_ARG)); |
2275 js.Expression jsHelper = | 2304 js.Expression jsHelper = |
2276 backend.emitter.staticFunctionAccess(convertToString); | 2305 backend.emitter.staticFunctionAccess(convertToString); |
2277 use(input); | 2306 use(input); |
2278 push(new js.Call(jsHelper, <js.Expression>[pop()], | 2307 push(new js.Call(jsHelper, <js.Expression>[pop()], |
2279 sourceInformation: node.sourceInformation)); | 2308 sourceInformation: node.sourceInformation)); |
2280 } | 2309 } |
2281 } | 2310 } |
2282 | 2311 |
2283 void visitLiteralList(HLiteralList node) { | 2312 void visitLiteralList(HLiteralList node) { |
2284 registry.registerInstantiatedClass(coreClasses.listClass); | 2313 registry.registerInstantiatedClass(coreClasses.listClass); |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2499 use(input); | 2528 use(input); |
2500 | 2529 |
2501 js.Expression jsClassReference = | 2530 js.Expression jsClassReference = |
2502 backend.emitter.constructorAccess(type.element); | 2531 backend.emitter.constructorAccess(type.element); |
2503 push(js.js('# instanceof #', [pop(), jsClassReference]) | 2532 push(js.js('# instanceof #', [pop(), jsClassReference]) |
2504 .withSourceInformation(sourceInformation)); | 2533 .withSourceInformation(sourceInformation)); |
2505 if (negative) { | 2534 if (negative) { |
2506 push(new js.Prefix('!', pop()) | 2535 push(new js.Prefix('!', pop()) |
2507 .withSourceInformation(sourceInformation)); | 2536 .withSourceInformation(sourceInformation)); |
2508 } | 2537 } |
2509 registry.registerInstantiatedType(type); | 2538 registry.registerInstantiation(type); |
2510 } | 2539 } |
2511 | 2540 |
2512 void handleNumberOrStringSupertypeCheck(HInstruction input, | 2541 void handleNumberOrStringSupertypeCheck(HInstruction input, |
2513 HInstruction interceptor, | 2542 HInstruction interceptor, |
2514 DartType type, | 2543 DartType type, |
2515 SourceInformation sourceInformation, | 2544 SourceInformation sourceInformation, |
2516 {bool negative: false}) { | 2545 {bool negative: false}) { |
2517 assert(!identical(type.element, coreClasses.listClass) && | 2546 assert(!identical(type.element, coreClasses.listClass) && |
2518 !Elements.isListSupertype(type.element, compiler) && | 2547 !Elements.isListSupertype(type.element, compiler) && |
2519 !Elements.isStringOnlySupertype(type.element, compiler)); | 2548 !Elements.isStringOnlySupertype(type.element, compiler)); |
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2824 returnType, | 2853 returnType, |
2825 new js.ArrayInitializer(parameterTypes), | 2854 new js.ArrayInitializer(parameterTypes), |
2826 new js.ObjectInitializer(namedParameters)]; | 2855 new js.ObjectInitializer(namedParameters)]; |
2827 push(js.js('#(#)', [accessHelper('buildNamedFunctionType'), arguments])); | 2856 push(js.js('#(#)', [accessHelper('buildNamedFunctionType'), arguments])); |
2828 } | 2857 } |
2829 } | 2858 } |
2830 | 2859 |
2831 void visitReadTypeVariable(HReadTypeVariable node) { | 2860 void visitReadTypeVariable(HReadTypeVariable node) { |
2832 TypeVariableElement element = node.dartType.element; | 2861 TypeVariableElement element = node.dartType.element; |
2833 Element helperElement = helpers.convertRtiToRuntimeType; | 2862 Element helperElement = helpers.convertRtiToRuntimeType; |
2834 registry.registerStaticUse(helperElement); | 2863 registry.registerStaticUse( |
| 2864 new StaticUse.staticInvoke(helperElement, CallStructure.ONE_ARG)); |
2835 | 2865 |
2836 use(node.inputs[0]); | 2866 use(node.inputs[0]); |
2837 if (node.hasReceiver) { | 2867 if (node.hasReceiver) { |
2838 if (backend.isInterceptorClass(element.enclosingClass)) { | 2868 if (backend.isInterceptorClass(element.enclosingClass)) { |
2839 int index = element.index; | 2869 int index = element.index; |
2840 js.Expression receiver = pop(); | 2870 js.Expression receiver = pop(); |
2841 js.Expression helper = backend.emitter | 2871 js.Expression helper = backend.emitter |
2842 .staticFunctionAccess(helperElement); | 2872 .staticFunctionAccess(helperElement); |
2843 push(js.js(r'#(#.$builtinTypeInfo && #.$builtinTypeInfo[#])', | 2873 push(js.js(r'#(#.$builtinTypeInfo && #.$builtinTypeInfo[#])', |
2844 [helper, receiver, receiver, js.js.number(index)])); | 2874 [helper, receiver, receiver, js.js.number(index)])); |
(...skipping 14 matching lines...) Expand all Loading... |
2859 for (HInstruction type in node.inputs) { | 2889 for (HInstruction type in node.inputs) { |
2860 use(type); | 2890 use(type); |
2861 typeArguments.add(pop()); | 2891 typeArguments.add(pop()); |
2862 } | 2892 } |
2863 | 2893 |
2864 ClassElement cls = node.dartType.element; | 2894 ClassElement cls = node.dartType.element; |
2865 var arguments = [backend.emitter.typeAccess(cls)]; | 2895 var arguments = [backend.emitter.typeAccess(cls)]; |
2866 if (!typeArguments.isEmpty) { | 2896 if (!typeArguments.isEmpty) { |
2867 arguments.add(new js.ArrayInitializer(typeArguments)); | 2897 arguments.add(new js.ArrayInitializer(typeArguments)); |
2868 } | 2898 } |
2869 push(js.js('#(#)', [accessHelper('buildInterfaceType'), arguments])); | 2899 push(js.js('#(#)', |
| 2900 [accessHelper('buildInterfaceType', arguments.length), arguments])); |
2870 } | 2901 } |
2871 | 2902 |
2872 void visitVoidType(HVoidType node) { | 2903 void visitVoidType(HVoidType node) { |
2873 push(js.js('#()', accessHelper('getVoidRuntimeType'))); | 2904 push(js.js('#()', accessHelper('getVoidRuntimeType'))); |
2874 } | 2905 } |
2875 | 2906 |
2876 void visitDynamicType(HDynamicType node) { | 2907 void visitDynamicType(HDynamicType node) { |
2877 push(js.js('#()', accessHelper('getDynamicRuntimeType'))); | 2908 push(js.js('#()', accessHelper('getDynamicRuntimeType'))); |
2878 } | 2909 } |
2879 | 2910 |
2880 js.PropertyAccess accessHelper(String name) { | 2911 js.PropertyAccess accessHelper(String name, [int argumentCount = 0]) { |
2881 Element helper = helpers.findHelper(name); | 2912 Element helper = helpers.findHelper(name); |
2882 if (helper == null) { | 2913 if (helper == null) { |
2883 // For mocked-up tests. | 2914 // For mocked-up tests. |
2884 return js.js('(void 0).$name'); | 2915 return js.js('(void 0).$name'); |
2885 } | 2916 } |
2886 registry.registerStaticUse(helper); | 2917 registry.registerStaticUse( |
| 2918 new StaticUse.staticInvoke(helper, |
| 2919 new CallStructure.unnamed(argumentCount))); |
2887 return backend.emitter.staticFunctionAccess(helper); | 2920 return backend.emitter.staticFunctionAccess(helper); |
2888 } | 2921 } |
2889 | 2922 |
2890 @override | 2923 @override |
2891 void visitRef(HRef node) { | 2924 void visitRef(HRef node) { |
2892 visit(node.value); | 2925 visit(node.value); |
2893 } | 2926 } |
2894 } | 2927 } |
OLD | NEW |