| 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 |