| 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 import 'dart:math' as math; | 5 import 'dart:math' as math; |
| 6 import '../common.dart'; | 6 import '../common.dart'; |
| 7 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; | 7 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
| 8 import '../common/tasks.dart' show CompilerTask; | 8 import '../common/tasks.dart' show CompilerTask; |
| 9 import '../compiler.dart' show Compiler; | 9 import '../compiler.dart' show Compiler; |
| 10 import '../constants/constant_system.dart'; | 10 import '../constants/constant_system.dart'; |
| 11 import '../constants/values.dart'; | 11 import '../constants/values.dart'; |
| 12 import '../core_types.dart' show CommonElements; | 12 import '../core_types.dart' show CommonElements; |
| 13 import '../dart_types.dart'; | 13 import '../dart_types.dart'; |
| 14 import '../elements/elements.dart'; | 14 import '../elements/elements.dart' |
| 15 show |
| 16 Entity, |
| 17 JumpTarget, |
| 18 LabelDefinition, |
| 19 Local, |
| 20 Name, |
| 21 AsyncMarker, |
| 22 ResolvedAst, |
| 23 FunctionElement; |
| 15 import '../elements/entities.dart'; | 24 import '../elements/entities.dart'; |
| 16 import '../io/source_information.dart'; | 25 import '../io/source_information.dart'; |
| 17 import '../js/js.dart' as js; | 26 import '../js/js.dart' as js; |
| 18 import '../js_backend/backend_helpers.dart' show BackendHelpers; | 27 import '../js_backend/backend_helpers.dart' show BackendHelpers; |
| 19 import '../js_backend/js_backend.dart'; | 28 import '../js_backend/js_backend.dart'; |
| 20 import '../js_emitter/js_emitter.dart' show NativeEmitter; | 29 import '../js_emitter/js_emitter.dart' show NativeEmitter; |
| 21 import '../native/native.dart' as native; | 30 import '../native/native.dart' as native; |
| 22 import '../types/types.dart'; | 31 import '../types/types.dart'; |
| 23 import '../universe/call_structure.dart' show CallStructure; | 32 import '../universe/call_structure.dart' show CallStructure; |
| 24 import '../universe/selector.dart' show Selector; | 33 import '../universe/selector.dart' show Selector; |
| (...skipping 762 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 787 | 796 |
| 788 bool visitAndOrInfo(HAndOrBlockInformation info) { | 797 bool visitAndOrInfo(HAndOrBlockInformation info) { |
| 789 return false; | 798 return false; |
| 790 } | 799 } |
| 791 | 800 |
| 792 bool visitTryInfo(HTryBlockInformation info) { | 801 bool visitTryInfo(HTryBlockInformation info) { |
| 793 js.Block body = generateStatementsInNewBlock(info.body); | 802 js.Block body = generateStatementsInNewBlock(info.body); |
| 794 js.Catch catchPart = null; | 803 js.Catch catchPart = null; |
| 795 js.Block finallyPart = null; | 804 js.Block finallyPart = null; |
| 796 if (info.catchBlock != null) { | 805 if (info.catchBlock != null) { |
| 797 void register(ClassElement classElement) { | 806 void register(ClassEntity classElement) { |
| 798 if (classElement != null) { | 807 if (classElement != null) { |
| 799 registry.registerInstantiatedClass(classElement); | 808 registry.registerInstantiatedClass(classElement); |
| 800 } | 809 } |
| 801 } | 810 } |
| 802 | 811 |
| 803 register(helpers.jsPlainJavaScriptObjectClass); | 812 register(helpers.jsPlainJavaScriptObjectClass); |
| 804 register(helpers.jsUnknownJavaScriptObjectClass); | 813 register(helpers.jsUnknownJavaScriptObjectClass); |
| 805 | 814 |
| 806 HLocalValue exception = info.catchVariable; | 815 HLocalValue exception = info.catchVariable; |
| 807 String name = variableNames.getName(exception); | 816 String name = variableNames.getName(exception); |
| (...skipping 826 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1634 .withSourceInformation(node.sourceInformation)); | 1643 .withSourceInformation(node.sourceInformation)); |
| 1635 registry.registerUseInterceptor(); | 1644 registry.registerUseInterceptor(); |
| 1636 } | 1645 } |
| 1637 } | 1646 } |
| 1638 | 1647 |
| 1639 visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 1648 visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
| 1640 use(node.receiver); | 1649 use(node.receiver); |
| 1641 js.Expression object = pop(); | 1650 js.Expression object = pop(); |
| 1642 String methodName; | 1651 String methodName; |
| 1643 List<js.Expression> arguments = visitArguments(node.inputs); | 1652 List<js.Expression> arguments = visitArguments(node.inputs); |
| 1644 MemberElement target = node.element; | 1653 MemberEntity target = node.element; |
| 1645 | 1654 |
| 1646 // TODO(herhut): The namer should return the appropriate backendname here. | 1655 // TODO(herhut): The namer should return the appropriate backendname here. |
| 1647 if (target != null && !node.isInterceptedCall) { | 1656 if (target != null && !node.isInterceptedCall) { |
| 1648 if (target == helpers.jsArrayAdd) { | 1657 if (target == helpers.jsArrayAdd) { |
| 1649 methodName = 'push'; | 1658 methodName = 'push'; |
| 1650 } else if (target == helpers.jsArrayRemoveLast) { | 1659 } else if (target == helpers.jsArrayRemoveLast) { |
| 1651 methodName = 'pop'; | 1660 methodName = 'pop'; |
| 1652 } else if (target == helpers.jsStringSplit) { | 1661 } else if (target == helpers.jsStringSplit) { |
| 1653 methodName = 'split'; | 1662 methodName = 'split'; |
| 1654 // Split returns a List, so we make sure the backend knows the | 1663 // Split returns a List, so we make sure the backend knows the |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1707 registry.registerUseInterceptor(); | 1716 registry.registerUseInterceptor(); |
| 1708 } | 1717 } |
| 1709 | 1718 |
| 1710 TypeMask getOptimizedSelectorFor( | 1719 TypeMask getOptimizedSelectorFor( |
| 1711 HInvokeDynamic node, Selector selector, TypeMask mask) { | 1720 HInvokeDynamic node, Selector selector, TypeMask mask) { |
| 1712 if (node.element != null) { | 1721 if (node.element != null) { |
| 1713 // Create an artificial type mask to make sure only | 1722 // Create an artificial type mask to make sure only |
| 1714 // [node.element] will be enqueued. We're not using the receiver | 1723 // [node.element] will be enqueued. We're not using the receiver |
| 1715 // type because our optimizations might end up in a state where the | 1724 // type because our optimizations might end up in a state where the |
| 1716 // invoke dynamic knows more than the receiver. | 1725 // invoke dynamic knows more than the receiver. |
| 1717 ClassElement enclosing = node.element.enclosingClass; | 1726 ClassEntity enclosing = node.element.enclosingClass; |
| 1718 if (closedWorld.isInstantiated(enclosing)) { | 1727 if (closedWorld.isInstantiated(enclosing)) { |
| 1719 return new TypeMask.nonNullExact(enclosing.declaration, closedWorld); | 1728 return closedWorld.commonMasks.createNonNullExact(enclosing); |
| 1720 } else { | 1729 } else { |
| 1721 // The element is mixed in so a non-null subtype mask is the most | 1730 // The element is mixed in so a non-null subtype mask is the most |
| 1722 // precise we have. | 1731 // precise we have. |
| 1723 assert(invariant(node, closedWorld.isUsedAsMixin(enclosing), | 1732 assert(invariant(node, closedWorld.isUsedAsMixin(enclosing), |
| 1724 message: "Element ${node.element} from $enclosing expected " | 1733 message: "Element ${node.element} from $enclosing expected " |
| 1725 "to be mixed in.")); | 1734 "to be mixed in.")); |
| 1726 return new TypeMask.nonNullSubtype(enclosing.declaration, closedWorld); | 1735 return closedWorld.commonMasks.createNonNullSubtype(enclosing); |
| 1727 } | 1736 } |
| 1728 } | 1737 } |
| 1729 // If [JSInvocationMirror._invokeOn] is enabled, and this call | 1738 // If [JSInvocationMirror._invokeOn] is enabled, and this call |
| 1730 // might hit a `noSuchMethod`, we register an untyped selector. | 1739 // might hit a `noSuchMethod`, we register an untyped selector. |
| 1731 return closedWorld.extendMaskIfReachesAll(selector, mask); | 1740 return closedWorld.extendMaskIfReachesAll(selector, mask); |
| 1732 } | 1741 } |
| 1733 | 1742 |
| 1734 void registerMethodInvoke(HInvokeDynamic node) { | 1743 void registerMethodInvoke(HInvokeDynamic node) { |
| 1735 Selector selector = node.selector; | 1744 Selector selector = node.selector; |
| 1736 | 1745 |
| 1737 // If we don't know what we're calling or if we are calling a getter, | 1746 // If we don't know what we're calling or if we are calling a getter, |
| 1738 // we need to register that fact that we may be calling a closure | 1747 // we need to register that fact that we may be calling a closure |
| 1739 // with the same arguments. | 1748 // with the same arguments. |
| 1740 MemberElement target = node.element; | 1749 MemberEntity target = node.element; |
| 1741 if (target == null || target.isGetter) { | 1750 if (target == null || target.isGetter) { |
| 1742 // TODO(kasperl): If we have a typed selector for the call, we | 1751 // TODO(kasperl): If we have a typed selector for the call, we |
| 1743 // may know something about the types of closures that need | 1752 // may know something about the types of closures that need |
| 1744 // the specific closure call method. | 1753 // the specific closure call method. |
| 1745 Selector call = new Selector.callClosureFrom(selector); | 1754 Selector call = new Selector.callClosureFrom(selector); |
| 1746 registry.registerDynamicUse(new DynamicUse(call, null)); | 1755 registry.registerDynamicUse(new DynamicUse(call, null)); |
| 1747 } | 1756 } |
| 1748 if (target != null) { | 1757 if (target != null) { |
| 1749 // This is a dynamic invocation which we have found to have a single | 1758 // This is a dynamic invocation which we have found to have a single |
| 1750 // target but for some reason haven't inlined. We are _still_ accessing | 1759 // target but for some reason haven't inlined. We are _still_ accessing |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1812 Selector call = new Selector.callClosureFrom(node.selector); | 1821 Selector call = new Selector.callClosureFrom(node.selector); |
| 1813 use(node.receiver); | 1822 use(node.receiver); |
| 1814 push(js | 1823 push(js |
| 1815 .propertyCall(pop(), backend.namer.invocationName(call), | 1824 .propertyCall(pop(), backend.namer.invocationName(call), |
| 1816 visitArguments(node.inputs)) | 1825 visitArguments(node.inputs)) |
| 1817 .withSourceInformation(node.sourceInformation)); | 1826 .withSourceInformation(node.sourceInformation)); |
| 1818 registry.registerDynamicUse(new DynamicUse(call, null)); | 1827 registry.registerDynamicUse(new DynamicUse(call, null)); |
| 1819 } | 1828 } |
| 1820 | 1829 |
| 1821 visitInvokeStatic(HInvokeStatic node) { | 1830 visitInvokeStatic(HInvokeStatic node) { |
| 1822 MemberElement element = node.element; | 1831 MemberEntity element = node.element; |
| 1823 List<DartType> instantiatedTypes = node.instantiatedTypes; | 1832 List<DartType> instantiatedTypes = node.instantiatedTypes; |
| 1824 | 1833 |
| 1825 if (instantiatedTypes != null && !instantiatedTypes.isEmpty) { | 1834 if (instantiatedTypes != null && !instantiatedTypes.isEmpty) { |
| 1826 instantiatedTypes.forEach((type) { | 1835 instantiatedTypes.forEach((type) { |
| 1827 registry.registerInstantiation(type); | 1836 registry.registerInstantiation(type); |
| 1828 }); | 1837 }); |
| 1829 } | 1838 } |
| 1830 | 1839 |
| 1831 List<js.Expression> arguments = visitArguments(node.inputs, start: 0); | 1840 List<js.Expression> arguments = visitArguments(node.inputs, start: 0); |
| 1832 | 1841 |
| 1833 if (element == backend.helpers.checkConcurrentModificationError) { | 1842 if (element == backend.helpers.checkConcurrentModificationError) { |
| 1834 // Manually inline the [checkConcurrentModificationError] function. This | 1843 // Manually inline the [checkConcurrentModificationError] function. This |
| 1835 // function is only called from a for-loop update. Ideally we would just | 1844 // function is only called from a for-loop update. Ideally we would just |
| 1836 // generate the conditionalcontrol flow in the builder but it adds basic | 1845 // generate the conditionalcontrol flow in the builder but it adds basic |
| 1837 // blocks in the loop update that interfere with other optimizations and | 1846 // blocks in the loop update that interfere with other optimizations and |
| 1838 // confuses loop recognition. | 1847 // confuses loop recognition. |
| 1839 | 1848 |
| 1840 assert(arguments.length == 2); | 1849 assert(arguments.length == 2); |
| 1841 Element throwFunction = backend.helpers.throwConcurrentModificationError; | 1850 FunctionEntity throwFunction = |
| 1851 backend.helpers.throwConcurrentModificationError; |
| 1842 registry.registerStaticUse( | 1852 registry.registerStaticUse( |
| 1843 new StaticUse.staticInvoke(throwFunction, CallStructure.ONE_ARG)); | 1853 new StaticUse.staticInvoke(throwFunction, CallStructure.ONE_ARG)); |
| 1844 | 1854 |
| 1845 // Calling using `(0, #)(#)` instead of `#(#)` separates the property load | 1855 // Calling using `(0, #)(#)` instead of `#(#)` separates the property load |
| 1846 // of the static function access from the call. For some reason this | 1856 // of the static function access from the call. For some reason this |
| 1847 // helps V8 see that the call never happens so V8 makes the call a | 1857 // helps V8 see that the call never happens so V8 makes the call a |
| 1848 // deoptimization. This removes the call from the optimized loop, making | 1858 // deoptimization. This removes the call from the optimized loop, making |
| 1849 // more optimizations available to the loop. This form is 50% faster on | 1859 // more optimizations available to the loop. This form is 50% faster on |
| 1850 // some small loop, almost as fast as loops with no concurrent | 1860 // some small loop, almost as fast as loops with no concurrent |
| 1851 // modification check. | 1861 // modification check. |
| 1852 push(js.js('# || (0, #)(#)', [ | 1862 push(js.js('# || (0, #)(#)', [ |
| 1853 arguments[0], | 1863 arguments[0], |
| 1854 backend.emitter.staticFunctionAccess(throwFunction), | 1864 backend.emitter.staticFunctionAccess(throwFunction), |
| 1855 arguments[1] | 1865 arguments[1] |
| 1856 ])); | 1866 ])); |
| 1857 } else { | 1867 } else { |
| 1858 CallStructure callStructure = new CallStructure.unnamed(arguments.length); | 1868 CallStructure callStructure = new CallStructure.unnamed(arguments.length); |
| 1859 registry.registerStaticUse(element.isConstructor | 1869 registry.registerStaticUse(element.isConstructor |
| 1860 ? new StaticUse.constructorInvoke(element, callStructure) | 1870 ? new StaticUse.constructorInvoke(element, callStructure) |
| 1861 : new StaticUse.staticInvoke(element, callStructure)); | 1871 : new StaticUse.staticInvoke(element, callStructure)); |
| 1862 push(backend.emitter.staticFunctionAccess(element)); | 1872 push(backend.emitter.staticFunctionAccess(element)); |
| 1863 push(new js.Call(pop(), arguments, | 1873 push(new js.Call(pop(), arguments, |
| 1864 sourceInformation: node.sourceInformation)); | 1874 sourceInformation: node.sourceInformation)); |
| 1865 } | 1875 } |
| 1866 } | 1876 } |
| 1867 | 1877 |
| 1868 visitInvokeSuper(HInvokeSuper node) { | 1878 visitInvokeSuper(HInvokeSuper node) { |
| 1869 MemberElement superElement = node.element; | 1879 MemberEntity superElement = node.element; |
| 1870 ClassElement superClass = superElement.enclosingClass; | 1880 ClassEntity superClass = superElement.enclosingClass; |
| 1871 if (superElement.isField) { | 1881 if (superElement.isField) { |
| 1872 js.Name fieldName = backend.namer.instanceFieldPropertyName(superElement); | 1882 js.Name fieldName = backend.namer.instanceFieldPropertyName(superElement); |
| 1873 use(node.inputs[0]); | 1883 use(node.inputs[0]); |
| 1874 js.PropertyAccess access = new js.PropertyAccess(pop(), fieldName) | 1884 js.PropertyAccess access = new js.PropertyAccess(pop(), fieldName) |
| 1875 .withSourceInformation(node.sourceInformation); | 1885 .withSourceInformation(node.sourceInformation); |
| 1876 if (node.isSetter) { | 1886 if (node.isSetter) { |
| 1877 registry.registerStaticUse(superElement.isSetter | 1887 registry.registerStaticUse(superElement.isSetter |
| 1878 ? new StaticUse.superSetterSet(superElement) | 1888 ? new StaticUse.superSetterSet(superElement) |
| 1879 : new StaticUse.superFieldSet(superElement)); | 1889 : new StaticUse.superFieldSet(superElement)); |
| 1880 use(node.value); | 1890 use(node.value); |
| 1881 push(new js.Assignment(access, pop()) | 1891 push(new js.Assignment(access, pop()) |
| 1882 .withSourceInformation(node.sourceInformation)); | 1892 .withSourceInformation(node.sourceInformation)); |
| 1883 } else { | 1893 } else { |
| 1884 registry.registerStaticUse(new StaticUse.superGet(superElement)); | 1894 registry.registerStaticUse(new StaticUse.superGet(superElement)); |
| 1885 push(access); | 1895 push(access); |
| 1886 } | 1896 } |
| 1887 } else { | 1897 } else { |
| 1888 Selector selector = node.selector; | 1898 Selector selector = node.selector; |
| 1889 if (!backend.maybeRegisterAliasedSuperMember(superElement, selector)) { | 1899 if (!backend.maybeRegisterAliasedSuperMember(superElement, selector)) { |
| 1890 js.Name methodName; | 1900 js.Name methodName; |
| 1891 if (selector.isGetter && !superElement.isGetter) { | 1901 if (selector.isGetter && !superElement.isGetter) { |
| 1892 // If this is a tear-off, register the fact that a tear-off closure | 1902 // If this is a tear-off, register the fact that a tear-off closure |
| 1893 // will be created, and that this tear-off must bypass ordinary | 1903 // will be created, and that this tear-off must bypass ordinary |
| 1894 // dispatch to ensure the super method is invoked. | 1904 // dispatch to ensure the super method is invoked. |
| 1895 FunctionElement helper = backend.helpers.closureFromTearOff; | 1905 FunctionEntity helper = backend.helpers.closureFromTearOff; |
| 1896 registry.registerStaticUse(new StaticUse.staticInvoke( | 1906 registry.registerStaticUse(new StaticUse.staticInvoke( |
| 1897 helper, new CallStructure.unnamed(helper.parameters.length))); | 1907 helper, compiler.codegenWorld.getCallStructureFor(helper))); |
| 1898 registry.registerStaticUse(new StaticUse.superTearOff(node.element)); | 1908 registry.registerStaticUse(new StaticUse.superTearOff(node.element)); |
| 1899 methodName = backend.namer.invocationName(selector); | 1909 methodName = backend.namer.invocationName(selector); |
| 1900 } else { | 1910 } else { |
| 1901 methodName = backend.namer.instanceMethodName(superElement); | 1911 methodName = backend.namer.instanceMethodName(superElement); |
| 1902 } | 1912 } |
| 1903 registry.registerStaticUse(new StaticUse.superInvoke( | 1913 registry.registerStaticUse(new StaticUse.superInvoke( |
| 1904 superElement, new CallStructure.unnamed(node.inputs.length))); | 1914 superElement, new CallStructure.unnamed(node.inputs.length))); |
| 1905 push(js.js('#.#.call(#)', [ | 1915 push(js.js('#.#.call(#)', [ |
| 1906 backend.emitter | 1916 backend.emitter |
| 1907 .prototypeAccess(superClass, hasBeenInstantiated: true), | 1917 .prototypeAccess(superClass, hasBeenInstantiated: true), |
| 1908 methodName, | 1918 methodName, |
| 1909 visitArguments(node.inputs, start: 0) | 1919 visitArguments(node.inputs, start: 0) |
| 1910 ]).withSourceInformation(node.sourceInformation)); | 1920 ]).withSourceInformation(node.sourceInformation)); |
| 1911 } else { | 1921 } else { |
| 1912 use(node.receiver); | 1922 use(node.receiver); |
| 1913 registry.registerStaticUse(new StaticUse.superInvoke( | 1923 registry.registerStaticUse(new StaticUse.superInvoke( |
| 1914 superElement, new CallStructure.unnamed(node.inputs.length - 1))); | 1924 superElement, new CallStructure.unnamed(node.inputs.length - 1))); |
| 1915 push(js.js('#.#(#)', [ | 1925 push(js.js('#.#(#)', [ |
| 1916 pop(), | 1926 pop(), |
| 1917 backend.namer.aliasedSuperMemberPropertyName(superElement), | 1927 backend.namer.aliasedSuperMemberPropertyName(superElement), |
| 1918 visitArguments(node.inputs, start: 1) | 1928 visitArguments(node.inputs, start: 1) |
| 1919 ]) // Skip receiver argument. | 1929 ]) // Skip receiver argument. |
| 1920 .withSourceInformation(node.sourceInformation)); | 1930 .withSourceInformation(node.sourceInformation)); |
| 1921 } | 1931 } |
| 1922 } | 1932 } |
| 1923 } | 1933 } |
| 1924 | 1934 |
| 1925 visitFieldGet(HFieldGet node) { | 1935 visitFieldGet(HFieldGet node) { |
| 1926 use(node.receiver); | 1936 use(node.receiver); |
| 1927 MemberElement element = node.element; | 1937 MemberEntity element = node.element; |
| 1928 if (node.isNullCheck) { | 1938 if (node.isNullCheck) { |
| 1929 // We access a JavaScript member we know all objects besides | 1939 // We access a JavaScript member we know all objects besides |
| 1930 // null and undefined have: V8 does not like accessing a member | 1940 // null and undefined have: V8 does not like accessing a member |
| 1931 // that does not exist. | 1941 // that does not exist. |
| 1932 push(new js.PropertyAccess.field(pop(), 'toString') | 1942 push(new js.PropertyAccess.field(pop(), 'toString') |
| 1933 .withSourceInformation(node.sourceInformation)); | 1943 .withSourceInformation(node.sourceInformation)); |
| 1934 } else if (element == helpers.jsIndexableLength) { | 1944 } else if (element == helpers.jsIndexableLength) { |
| 1935 // We're accessing a native JavaScript property called 'length' | 1945 // We're accessing a native JavaScript property called 'length' |
| 1936 // on a JS String or a JS array. Therefore, the name of that | 1946 // on a JS String or a JS array. Therefore, the name of that |
| 1937 // property should not be mangled. | 1947 // property should not be mangled. |
| 1938 push(new js.PropertyAccess.field(pop(), 'length') | 1948 push(new js.PropertyAccess.field(pop(), 'length') |
| 1939 .withSourceInformation(node.sourceInformation)); | 1949 .withSourceInformation(node.sourceInformation)); |
| 1940 } else { | 1950 } else { |
| 1941 js.Name name = backend.namer.instanceFieldPropertyName(element); | 1951 FieldEntity field = element; |
| 1952 js.Name name = backend.namer.instanceFieldPropertyName(field); |
| 1942 push(new js.PropertyAccess(pop(), name) | 1953 push(new js.PropertyAccess(pop(), name) |
| 1943 .withSourceInformation(node.sourceInformation)); | 1954 .withSourceInformation(node.sourceInformation)); |
| 1944 registry.registerStaticUse(new StaticUse.fieldGet(element)); | 1955 registry.registerStaticUse(new StaticUse.fieldGet(field)); |
| 1945 } | 1956 } |
| 1946 } | 1957 } |
| 1947 | 1958 |
| 1948 visitFieldSet(HFieldSet node) { | 1959 visitFieldSet(HFieldSet node) { |
| 1949 MemberElement element = node.element; | 1960 MemberEntity element = node.element; |
| 1950 registry.registerStaticUse(new StaticUse.fieldSet(element)); | 1961 registry.registerStaticUse(new StaticUse.fieldSet(element)); |
| 1951 js.Name name = backend.namer.instanceFieldPropertyName(element); | 1962 js.Name name = backend.namer.instanceFieldPropertyName(element); |
| 1952 use(node.receiver); | 1963 use(node.receiver); |
| 1953 js.Expression receiver = pop(); | 1964 js.Expression receiver = pop(); |
| 1954 use(node.value); | 1965 use(node.value); |
| 1955 push(new js.Assignment(new js.PropertyAccess(receiver, name), pop()) | 1966 push(new js.Assignment(new js.PropertyAccess(receiver, name), pop()) |
| 1956 .withSourceInformation(node.sourceInformation)); | 1967 .withSourceInformation(node.sourceInformation)); |
| 1957 } | 1968 } |
| 1958 | 1969 |
| 1959 visitReadModifyWrite(HReadModifyWrite node) { | 1970 visitReadModifyWrite(HReadModifyWrite node) { |
| 1960 FieldElement element = node.element; | 1971 FieldEntity element = node.element; |
| 1961 registry.registerStaticUse(new StaticUse.fieldGet(element)); | 1972 registry.registerStaticUse(new StaticUse.fieldGet(element)); |
| 1962 registry.registerStaticUse(new StaticUse.fieldSet(element)); | 1973 registry.registerStaticUse(new StaticUse.fieldSet(element)); |
| 1963 js.Name name = backend.namer.instanceFieldPropertyName(element); | 1974 js.Name name = backend.namer.instanceFieldPropertyName(element); |
| 1964 use(node.receiver); | 1975 use(node.receiver); |
| 1965 js.Expression fieldReference = new js.PropertyAccess(pop(), name); | 1976 js.Expression fieldReference = new js.PropertyAccess(pop(), name); |
| 1966 if (node.isPreOp) { | 1977 if (node.isPreOp) { |
| 1967 push(new js.Prefix(node.jsOp, fieldReference) | 1978 push(new js.Prefix(node.jsOp, fieldReference) |
| 1968 .withSourceInformation(node.sourceInformation)); | 1979 .withSourceInformation(node.sourceInformation)); |
| 1969 } else if (node.isPostOp) { | 1980 } else if (node.isPostOp) { |
| 1970 push(new js.Postfix(node.jsOp, fieldReference) | 1981 push(new js.Postfix(node.jsOp, fieldReference) |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2048 void generateConstant( | 2059 void generateConstant( |
| 2049 ConstantValue constant, SourceInformation sourceInformation) { | 2060 ConstantValue constant, SourceInformation sourceInformation) { |
| 2050 if (constant.isFunction) { | 2061 if (constant.isFunction) { |
| 2051 FunctionConstantValue function = constant; | 2062 FunctionConstantValue function = constant; |
| 2052 registry.registerStaticUse(new StaticUse.staticTearOff(function.element)); | 2063 registry.registerStaticUse(new StaticUse.staticTearOff(function.element)); |
| 2053 } | 2064 } |
| 2054 if (constant.isType) { | 2065 if (constant.isType) { |
| 2055 // If the type is a web component, we need to ensure the constructors are | 2066 // If the type is a web component, we need to ensure the constructors are |
| 2056 // available to 'upgrade' the native object. | 2067 // available to 'upgrade' the native object. |
| 2057 TypeConstantValue type = constant; | 2068 TypeConstantValue type = constant; |
| 2058 Element element = type.representedType.element; | 2069 if (type.representedType.isInterfaceType) { |
| 2059 if (element != null && element.isClass) { | 2070 registry.registerTypeConstant(type.representedType.element); |
| 2060 registry.registerTypeConstant(element); | |
| 2061 } | 2071 } |
| 2062 } | 2072 } |
| 2063 js.Expression expression = backend.emitter.constantReference(constant); | 2073 js.Expression expression = backend.emitter.constantReference(constant); |
| 2064 if (!constant.isDummy) { | 2074 if (!constant.isDummy) { |
| 2065 // TODO(johnniwinther): Support source information on synthetic constants. | 2075 // TODO(johnniwinther): Support source information on synthetic constants. |
| 2066 expression = expression.withSourceInformation(sourceInformation); | 2076 expression = expression.withSourceInformation(sourceInformation); |
| 2067 } | 2077 } |
| 2068 push(expression); | 2078 push(expression); |
| 2069 } | 2079 } |
| 2070 | 2080 |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2274 currentContainer = oldContainer; | 2284 currentContainer = oldContainer; |
| 2275 thenBody = unwrapStatement(thenBody); | 2285 thenBody = unwrapStatement(thenBody); |
| 2276 pushStatement(new js.If.noElse(underOver, thenBody) | 2286 pushStatement(new js.If.noElse(underOver, thenBody) |
| 2277 .withSourceInformation(node.sourceInformation)); | 2287 .withSourceInformation(node.sourceInformation)); |
| 2278 } else { | 2288 } else { |
| 2279 generateThrowWithHelper( | 2289 generateThrowWithHelper( |
| 2280 helpers.throwIndexOutOfRangeException, [node.array, node.index]); | 2290 helpers.throwIndexOutOfRangeException, [node.array, node.index]); |
| 2281 } | 2291 } |
| 2282 } | 2292 } |
| 2283 | 2293 |
| 2284 void generateThrowWithHelper(Element helper, argument, | 2294 void generateThrowWithHelper(FunctionEntity helper, argument, |
| 2285 {SourceInformation sourceInformation}) { | 2295 {SourceInformation sourceInformation}) { |
| 2286 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); | 2296 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); |
| 2287 List arguments = []; | 2297 List arguments = []; |
| 2288 if (argument is List) { | 2298 if (argument is List) { |
| 2289 argument.forEach((instruction) { | 2299 argument.forEach((instruction) { |
| 2290 use(instruction); | 2300 use(instruction); |
| 2291 arguments.add(pop()); | 2301 arguments.add(pop()); |
| 2292 }); | 2302 }); |
| 2293 } else { | 2303 } else { |
| 2294 use(argument); | 2304 use(argument); |
| 2295 arguments.add(pop()); | 2305 arguments.add(pop()); |
| 2296 } | 2306 } |
| 2297 registry.registerStaticUse(new StaticUse.staticInvoke( | 2307 registry.registerStaticUse(new StaticUse.staticInvoke( |
| 2298 helper, new CallStructure.unnamed(arguments.length))); | 2308 helper, new CallStructure.unnamed(arguments.length))); |
| 2299 js.Call value = new js.Call(jsHelper, arguments.toList(growable: false), | 2309 js.Call value = new js.Call(jsHelper, arguments.toList(growable: false), |
| 2300 sourceInformation: sourceInformation); | 2310 sourceInformation: sourceInformation); |
| 2301 // BUG(4906): Using throw/return here adds to the size of the generated code | 2311 // BUG(4906): Using throw/return here adds to the size of the generated code |
| 2302 // but it has the advantage of explicitly telling the JS engine that | 2312 // but it has the advantage of explicitly telling the JS engine that |
| 2303 // this code path will terminate abruptly. Needs more work. | 2313 // this code path will terminate abruptly. Needs more work. |
| 2304 if (helper == helpers.wrapExceptionHelper) { | 2314 if (helper == helpers.wrapExceptionHelper) { |
| 2305 pushStatement( | 2315 pushStatement( |
| 2306 new js.Throw(value).withSourceInformation(sourceInformation)); | 2316 new js.Throw(value).withSourceInformation(sourceInformation)); |
| 2307 } else { | 2317 } else { |
| 2308 Element element = work.element; | 2318 Entity element = work.element; |
| 2309 if (element is FunctionElement && element.asyncMarker.isYielding) { | 2319 if (element is FunctionElement && element.asyncMarker.isYielding) { |
| 2310 // `return <expr>;` is illegal in a sync* or async* function. | 2320 // `return <expr>;` is illegal in a sync* or async* function. |
| 2311 // To have the async-translator working, we avoid introducing | 2321 // To have the async-translator working, we avoid introducing |
| 2312 // `return` nodes. | 2322 // `return` nodes. |
| 2313 pushStatement(new js.ExpressionStatement(value) | 2323 pushStatement(new js.ExpressionStatement(value) |
| 2314 .withSourceInformation(sourceInformation)); | 2324 .withSourceInformation(sourceInformation)); |
| 2315 } else { | 2325 } else { |
| 2316 pushStatement( | 2326 pushStatement( |
| 2317 new js.Return(value).withSourceInformation(sourceInformation)); | 2327 new js.Return(value).withSourceInformation(sourceInformation)); |
| 2318 } | 2328 } |
| 2319 } | 2329 } |
| 2320 } | 2330 } |
| 2321 | 2331 |
| 2322 visitThrowExpression(HThrowExpression node) { | 2332 visitThrowExpression(HThrowExpression node) { |
| 2323 HInstruction argument = node.inputs[0]; | 2333 HInstruction argument = node.inputs[0]; |
| 2324 use(argument); | 2334 use(argument); |
| 2325 | 2335 |
| 2326 Element helper = helpers.throwExpressionHelper; | 2336 FunctionEntity helper = helpers.throwExpressionHelper; |
| 2327 registry.registerStaticUse( | 2337 registry.registerStaticUse( |
| 2328 new StaticUse.staticInvoke(helper, CallStructure.ONE_ARG)); | 2338 new StaticUse.staticInvoke(helper, CallStructure.ONE_ARG)); |
| 2329 | 2339 |
| 2330 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); | 2340 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); |
| 2331 js.Call value = new js.Call(jsHelper, [pop()]) | 2341 js.Call value = new js.Call(jsHelper, [pop()]) |
| 2332 .withSourceInformation(node.sourceInformation); | 2342 .withSourceInformation(node.sourceInformation); |
| 2333 push(value); | 2343 push(value); |
| 2334 } | 2344 } |
| 2335 | 2345 |
| 2336 void visitSwitch(HSwitch node) { | 2346 void visitSwitch(HSwitch node) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2390 if (node.usedBy.length == 1 && | 2400 if (node.usedBy.length == 1 && |
| 2391 node.usedBy[0] is HStringConcat && | 2401 node.usedBy[0] is HStringConcat && |
| 2392 node.usedBy[0].inputs[1] == node) { | 2402 node.usedBy[0].inputs[1] == node) { |
| 2393 // The context is already <string> + value. | 2403 // The context is already <string> + value. |
| 2394 } else { | 2404 } else { |
| 2395 // Force an empty string for the first operand. | 2405 // Force an empty string for the first operand. |
| 2396 push(new js.Binary('+', js.string(""), pop()) | 2406 push(new js.Binary('+', js.string(""), pop()) |
| 2397 .withSourceInformation(node.sourceInformation)); | 2407 .withSourceInformation(node.sourceInformation)); |
| 2398 } | 2408 } |
| 2399 } else { | 2409 } else { |
| 2400 Element convertToString = backend.helpers.stringInterpolationHelper; | 2410 FunctionEntity convertToString = |
| 2411 backend.helpers.stringInterpolationHelper; |
| 2401 registry.registerStaticUse( | 2412 registry.registerStaticUse( |
| 2402 new StaticUse.staticInvoke(convertToString, CallStructure.ONE_ARG)); | 2413 new StaticUse.staticInvoke(convertToString, CallStructure.ONE_ARG)); |
| 2403 js.Expression jsHelper = | 2414 js.Expression jsHelper = |
| 2404 backend.emitter.staticFunctionAccess(convertToString); | 2415 backend.emitter.staticFunctionAccess(convertToString); |
| 2405 use(input); | 2416 use(input); |
| 2406 push(new js.Call(jsHelper, <js.Expression>[pop()], | 2417 push(new js.Call(jsHelper, <js.Expression>[pop()], |
| 2407 sourceInformation: node.sourceInformation)); | 2418 sourceInformation: node.sourceInformation)); |
| 2408 } | 2419 } |
| 2409 } | 2420 } |
| 2410 | 2421 |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2549 } | 2560 } |
| 2550 | 2561 |
| 2551 void checkNonNull(HInstruction input) { | 2562 void checkNonNull(HInstruction input) { |
| 2552 use(input); | 2563 use(input); |
| 2553 push(new js.Binary('!=', pop(), new js.LiteralNull())); | 2564 push(new js.Binary('!=', pop(), new js.LiteralNull())); |
| 2554 } | 2565 } |
| 2555 | 2566 |
| 2556 void checkType(HInstruction input, HInstruction interceptor, DartType type, | 2567 void checkType(HInstruction input, HInstruction interceptor, DartType type, |
| 2557 SourceInformation sourceInformation, | 2568 SourceInformation sourceInformation, |
| 2558 {bool negative: false}) { | 2569 {bool negative: false}) { |
| 2559 Element element = type.element; | 2570 if (type.isInterfaceType) { |
| 2560 if (element == helpers.jsArrayClass) { | 2571 InterfaceType interfaceType = type; |
| 2561 checkArray(input, negative ? '!==' : '==='); | 2572 ClassEntity element = interfaceType.element; |
| 2562 return; | 2573 if (element == helpers.jsArrayClass) { |
| 2563 } else if (element == helpers.jsMutableArrayClass) { | 2574 checkArray(input, negative ? '!==' : '==='); |
| 2564 if (negative) { | 2575 return; |
| 2565 checkImmutableArray(input); | 2576 } else if (element == helpers.jsMutableArrayClass) { |
| 2566 } else { | 2577 if (negative) { |
| 2567 checkMutableArray(input); | 2578 checkImmutableArray(input); |
| 2579 } else { |
| 2580 checkMutableArray(input); |
| 2581 } |
| 2582 return; |
| 2583 } else if (element == helpers.jsExtendableArrayClass) { |
| 2584 if (negative) { |
| 2585 checkFixedArray(input); |
| 2586 } else { |
| 2587 checkExtendableArray(input); |
| 2588 } |
| 2589 return; |
| 2590 } else if (element == helpers.jsFixedArrayClass) { |
| 2591 if (negative) { |
| 2592 checkExtendableArray(input); |
| 2593 } else { |
| 2594 checkFixedArray(input); |
| 2595 } |
| 2596 return; |
| 2597 } else if (element == helpers.jsUnmodifiableArrayClass) { |
| 2598 if (negative) { |
| 2599 checkMutableArray(input); |
| 2600 } else { |
| 2601 checkImmutableArray(input); |
| 2602 } |
| 2603 return; |
| 2568 } | 2604 } |
| 2569 return; | |
| 2570 } else if (element == helpers.jsExtendableArrayClass) { | |
| 2571 if (negative) { | |
| 2572 checkFixedArray(input); | |
| 2573 } else { | |
| 2574 checkExtendableArray(input); | |
| 2575 } | |
| 2576 return; | |
| 2577 } else if (element == helpers.jsFixedArrayClass) { | |
| 2578 if (negative) { | |
| 2579 checkExtendableArray(input); | |
| 2580 } else { | |
| 2581 checkFixedArray(input); | |
| 2582 } | |
| 2583 return; | |
| 2584 } else if (element == helpers.jsUnmodifiableArrayClass) { | |
| 2585 if (negative) { | |
| 2586 checkMutableArray(input); | |
| 2587 } else { | |
| 2588 checkImmutableArray(input); | |
| 2589 } | |
| 2590 return; | |
| 2591 } | 2605 } |
| 2592 if (interceptor != null) { | 2606 if (interceptor != null) { |
| 2593 checkTypeViaProperty(interceptor, type, sourceInformation, | 2607 checkTypeViaProperty(interceptor, type, sourceInformation, |
| 2594 negative: negative); | 2608 negative: negative); |
| 2595 } else { | 2609 } else { |
| 2596 checkTypeViaProperty(input, type, sourceInformation, negative: negative); | 2610 checkTypeViaProperty(input, type, sourceInformation, negative: negative); |
| 2597 } | 2611 } |
| 2598 } | 2612 } |
| 2599 | 2613 |
| 2600 void checkTypeViaProperty( | 2614 void checkTypeViaProperty( |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2632 registry.registerInstantiation(type); | 2646 registry.registerInstantiation(type); |
| 2633 } | 2647 } |
| 2634 | 2648 |
| 2635 void handleNumberOrStringSupertypeCheck( | 2649 void handleNumberOrStringSupertypeCheck( |
| 2636 HInstruction input, | 2650 HInstruction input, |
| 2637 HInstruction interceptor, | 2651 HInstruction interceptor, |
| 2638 DartType type, | 2652 DartType type, |
| 2639 SourceInformation sourceInformation, | 2653 SourceInformation sourceInformation, |
| 2640 {bool negative: false}) { | 2654 {bool negative: false}) { |
| 2641 assert(!identical(type.element, commonElements.listClass) && | 2655 assert(!identical(type.element, commonElements.listClass) && |
| 2642 !Elements.isListSupertype(type.element, commonElements) && | 2656 !commonElements.isListSupertype(type.element) && |
| 2643 !Elements.isStringOnlySupertype(type.element, commonElements)); | 2657 !commonElements.isStringOnlySupertype(type.element)); |
| 2644 String relation = negative ? '!==' : '==='; | 2658 String relation = negative ? '!==' : '==='; |
| 2645 checkNum(input, relation, sourceInformation); | 2659 checkNum(input, relation, sourceInformation); |
| 2646 js.Expression numberTest = pop(); | 2660 js.Expression numberTest = pop(); |
| 2647 checkString(input, relation, sourceInformation); | 2661 checkString(input, relation, sourceInformation); |
| 2648 js.Expression stringTest = pop(); | 2662 js.Expression stringTest = pop(); |
| 2649 checkObject(input, relation, sourceInformation); | 2663 checkObject(input, relation, sourceInformation); |
| 2650 js.Expression objectTest = pop(); | 2664 js.Expression objectTest = pop(); |
| 2651 checkType(input, interceptor, type, sourceInformation, negative: negative); | 2665 checkType(input, interceptor, type, sourceInformation, negative: negative); |
| 2652 String combiner = negative ? '&&' : '||'; | 2666 String combiner = negative ? '&&' : '||'; |
| 2653 String combiner2 = negative ? '||' : '&&'; | 2667 String combiner2 = negative ? '||' : '&&'; |
| 2654 push(new js.Binary( | 2668 push(new js.Binary( |
| 2655 combiner, | 2669 combiner, |
| 2656 new js.Binary(combiner, numberTest, stringTest) | 2670 new js.Binary(combiner, numberTest, stringTest) |
| 2657 .withSourceInformation(sourceInformation), | 2671 .withSourceInformation(sourceInformation), |
| 2658 new js.Binary(combiner2, objectTest, pop()) | 2672 new js.Binary(combiner2, objectTest, pop()) |
| 2659 .withSourceInformation(sourceInformation)) | 2673 .withSourceInformation(sourceInformation)) |
| 2660 .withSourceInformation(sourceInformation)); | 2674 .withSourceInformation(sourceInformation)); |
| 2661 } | 2675 } |
| 2662 | 2676 |
| 2663 void handleStringSupertypeCheck(HInstruction input, HInstruction interceptor, | 2677 void handleStringSupertypeCheck(HInstruction input, HInstruction interceptor, |
| 2664 DartType type, SourceInformation sourceInformation, | 2678 DartType type, SourceInformation sourceInformation, |
| 2665 {bool negative: false}) { | 2679 {bool negative: false}) { |
| 2666 assert(!identical(type.element, commonElements.listClass) && | 2680 assert(!identical(type.element, commonElements.listClass) && |
| 2667 !Elements.isListSupertype(type.element, commonElements) && | 2681 !commonElements.isListSupertype(type.element) && |
| 2668 !Elements.isNumberOrStringSupertype(type.element, commonElements)); | 2682 !commonElements.isNumberOrStringSupertype(type.element)); |
| 2669 String relation = negative ? '!==' : '==='; | 2683 String relation = negative ? '!==' : '==='; |
| 2670 checkString(input, relation, sourceInformation); | 2684 checkString(input, relation, sourceInformation); |
| 2671 js.Expression stringTest = pop(); | 2685 js.Expression stringTest = pop(); |
| 2672 checkObject(input, relation, sourceInformation); | 2686 checkObject(input, relation, sourceInformation); |
| 2673 js.Expression objectTest = pop(); | 2687 js.Expression objectTest = pop(); |
| 2674 checkType(input, interceptor, type, sourceInformation, negative: negative); | 2688 checkType(input, interceptor, type, sourceInformation, negative: negative); |
| 2675 String combiner = negative ? '||' : '&&'; | 2689 String combiner = negative ? '||' : '&&'; |
| 2676 push(new js.Binary(negative ? '&&' : '||', stringTest, | 2690 push(new js.Binary(negative ? '&&' : '||', stringTest, |
| 2677 new js.Binary(combiner, objectTest, pop()))); | 2691 new js.Binary(combiner, objectTest, pop()))); |
| 2678 } | 2692 } |
| 2679 | 2693 |
| 2680 void handleListOrSupertypeCheck(HInstruction input, HInstruction interceptor, | 2694 void handleListOrSupertypeCheck(HInstruction input, HInstruction interceptor, |
| 2681 DartType type, SourceInformation sourceInformation, | 2695 DartType type, SourceInformation sourceInformation, |
| 2682 {bool negative: false}) { | 2696 {bool negative: false}) { |
| 2683 assert(!identical(type.element, commonElements.stringClass) && | 2697 assert(!identical(type.element, commonElements.stringClass) && |
| 2684 !Elements.isStringOnlySupertype(type.element, commonElements) && | 2698 !commonElements.isStringOnlySupertype(type.element) && |
| 2685 !Elements.isNumberOrStringSupertype(type.element, commonElements)); | 2699 !commonElements.isNumberOrStringSupertype(type.element)); |
| 2686 String relation = negative ? '!==' : '==='; | 2700 String relation = negative ? '!==' : '==='; |
| 2687 checkObject(input, relation, sourceInformation); | 2701 checkObject(input, relation, sourceInformation); |
| 2688 js.Expression objectTest = pop(); | 2702 js.Expression objectTest = pop(); |
| 2689 checkArray(input, relation); | 2703 checkArray(input, relation); |
| 2690 js.Expression arrayTest = pop(); | 2704 js.Expression arrayTest = pop(); |
| 2691 checkType(input, interceptor, type, sourceInformation, negative: negative); | 2705 checkType(input, interceptor, type, sourceInformation, negative: negative); |
| 2692 String combiner = negative ? '&&' : '||'; | 2706 String combiner = negative ? '&&' : '||'; |
| 2693 push(new js.Binary(negative ? '||' : '&&', objectTest, | 2707 push(new js.Binary(negative ? '||' : '&&', objectTest, |
| 2694 new js.Binary(combiner, arrayTest, pop())) | 2708 new js.Binary(combiner, arrayTest, pop())) |
| 2695 .withSourceInformation(sourceInformation)); | 2709 .withSourceInformation(sourceInformation)); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2712 // be changed to match. | 2726 // be changed to match. |
| 2713 assert(relation == '===' || relation == '!=='); | 2727 assert(relation == '===' || relation == '!=='); |
| 2714 bool negative = relation == '!=='; | 2728 bool negative = relation == '!=='; |
| 2715 | 2729 |
| 2716 if (node.isVariableCheck || node.isCompoundCheck) { | 2730 if (node.isVariableCheck || node.isCompoundCheck) { |
| 2717 use(node.checkCall); | 2731 use(node.checkCall); |
| 2718 if (negative) push(new js.Prefix('!', pop())); | 2732 if (negative) push(new js.Prefix('!', pop())); |
| 2719 } else { | 2733 } else { |
| 2720 assert(node.isRawCheck); | 2734 assert(node.isRawCheck); |
| 2721 HInstruction interceptor = node.interceptor; | 2735 HInstruction interceptor = node.interceptor; |
| 2722 ClassElement objectClass = commonElements.objectClass; | 2736 InterfaceType interfaceType = type; |
| 2723 Element element = type.element; | 2737 ClassEntity element = interfaceType.element; |
| 2724 if (element == commonElements.nullClass) { | 2738 if (element == commonElements.nullClass) { |
| 2725 if (negative) { | 2739 if (negative) { |
| 2726 checkNonNull(input); | 2740 checkNonNull(input); |
| 2727 } else { | 2741 } else { |
| 2728 checkNull(input); | 2742 checkNull(input); |
| 2729 } | 2743 } |
| 2730 } else if (identical(element, objectClass) || type.treatAsDynamic) { | 2744 } else if (element == |
| 2745 commonElements.objectClass /* || type.treatAsDynamic*/) { |
| 2731 // The constant folder also does this optimization, but we make | 2746 // The constant folder also does this optimization, but we make |
| 2732 // it safe by assuming it may have not run. | 2747 // it safe by assuming it may have not run. |
| 2733 push(newLiteralBool(!negative, sourceInformation)); | 2748 push(newLiteralBool(!negative, sourceInformation)); |
| 2734 } else if (element == commonElements.stringClass) { | 2749 } else if (element == commonElements.stringClass) { |
| 2735 checkString(input, relation, sourceInformation); | 2750 checkString(input, relation, sourceInformation); |
| 2736 } else if (element == commonElements.doubleClass) { | 2751 } else if (element == commonElements.doubleClass) { |
| 2737 checkDouble(input, relation, sourceInformation); | 2752 checkDouble(input, relation, sourceInformation); |
| 2738 } else if (element == commonElements.numClass) { | 2753 } else if (element == commonElements.numClass) { |
| 2739 checkNum(input, relation, sourceInformation); | 2754 checkNum(input, relation, sourceInformation); |
| 2740 } else if (element == commonElements.boolClass) { | 2755 } else if (element == commonElements.boolClass) { |
| 2741 checkBool(input, relation, sourceInformation); | 2756 checkBool(input, relation, sourceInformation); |
| 2742 } else if (element == commonElements.intClass) { | 2757 } else if (element == commonElements.intClass) { |
| 2743 // The is check in the code tells us that it might not be an | 2758 // The is check in the code tells us that it might not be an |
| 2744 // int. So we do a typeof first to avoid possible | 2759 // int. So we do a typeof first to avoid possible |
| 2745 // deoptimizations on the JS engine due to the Math.floor check. | 2760 // deoptimizations on the JS engine due to the Math.floor check. |
| 2746 checkNum(input, relation, sourceInformation); | 2761 checkNum(input, relation, sourceInformation); |
| 2747 js.Expression numTest = pop(); | 2762 js.Expression numTest = pop(); |
| 2748 checkBigInt(input, relation, sourceInformation); | 2763 checkBigInt(input, relation, sourceInformation); |
| 2749 push(new js.Binary(negative ? '||' : '&&', numTest, pop()) | 2764 push(new js.Binary(negative ? '||' : '&&', numTest, pop()) |
| 2750 .withSourceInformation(sourceInformation)); | 2765 .withSourceInformation(sourceInformation)); |
| 2751 } else if (node.useInstanceOf) { | 2766 } else if (node.useInstanceOf) { |
| 2752 assert(interceptor == null); | 2767 assert(interceptor == null); |
| 2753 checkTypeViaInstanceof(input, type, sourceInformation, | 2768 checkTypeViaInstanceof(input, type, sourceInformation, |
| 2754 negative: negative); | 2769 negative: negative); |
| 2755 } else if (Elements.isNumberOrStringSupertype(element, commonElements)) { | 2770 } else if (commonElements.isNumberOrStringSupertype(element)) { |
| 2756 handleNumberOrStringSupertypeCheck( | 2771 handleNumberOrStringSupertypeCheck( |
| 2757 input, interceptor, type, sourceInformation, | 2772 input, interceptor, type, sourceInformation, |
| 2758 negative: negative); | 2773 negative: negative); |
| 2759 } else if (Elements.isStringOnlySupertype(element, commonElements)) { | 2774 } else if (commonElements.isStringOnlySupertype(element)) { |
| 2760 handleStringSupertypeCheck(input, interceptor, type, sourceInformation, | 2775 handleStringSupertypeCheck(input, interceptor, type, sourceInformation, |
| 2761 negative: negative); | 2776 negative: negative); |
| 2762 } else if (identical(element, commonElements.listClass) || | 2777 } else if (element == commonElements.listClass || |
| 2763 Elements.isListSupertype(element, commonElements)) { | 2778 commonElements.isListSupertype(element)) { |
| 2764 handleListOrSupertypeCheck(input, interceptor, type, sourceInformation, | 2779 handleListOrSupertypeCheck(input, interceptor, type, sourceInformation, |
| 2765 negative: negative); | 2780 negative: negative); |
| 2766 } else if (type.isFunctionType) { | 2781 } else if (type.isFunctionType) { |
| 2767 checkType(input, interceptor, type, sourceInformation, | 2782 checkType(input, interceptor, type, sourceInformation, |
| 2768 negative: negative); | 2783 negative: negative); |
| 2769 } else if ((input.canBePrimitive(closedWorld) && | 2784 } else if ((input.canBePrimitive(closedWorld) && |
| 2770 !input.canBePrimitiveArray(closedWorld)) || | 2785 !input.canBePrimitiveArray(closedWorld)) || |
| 2771 input.canBeNull()) { | 2786 input.canBeNull()) { |
| 2772 checkObject(input, relation, node.sourceInformation); | 2787 checkObject(input, relation, node.sourceInformation); |
| 2773 js.Expression objectTest = pop(); | 2788 js.Expression objectTest = pop(); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2854 } | 2869 } |
| 2855 currentContainer = oldContainer; | 2870 currentContainer = oldContainer; |
| 2856 body = unwrapStatement(body); | 2871 body = unwrapStatement(body); |
| 2857 pushStatement(new js.If.noElse(test, body) | 2872 pushStatement(new js.If.noElse(test, body) |
| 2858 .withSourceInformation(node.sourceInformation)); | 2873 .withSourceInformation(node.sourceInformation)); |
| 2859 return; | 2874 return; |
| 2860 } | 2875 } |
| 2861 | 2876 |
| 2862 assert(node.isCheckedModeCheck || node.isCastTypeCheck); | 2877 assert(node.isCheckedModeCheck || node.isCastTypeCheck); |
| 2863 DartType type = node.typeExpression; | 2878 DartType type = node.typeExpression; |
| 2864 assert(type.kind != TypeKind.TYPEDEF); | 2879 assert(!type.isTypedef); |
| 2865 if (type.isFunctionType) { | 2880 if (type.isFunctionType) { |
| 2866 // TODO(5022): We currently generate $isFunction checks for | 2881 // TODO(5022): We currently generate $isFunction checks for |
| 2867 // function types. | 2882 // function types. |
| 2868 registry.registerTypeUse( | 2883 registry.registerTypeUse( |
| 2869 new TypeUse.isCheck(compiler.commonElements.functionType)); | 2884 new TypeUse.isCheck(compiler.commonElements.functionType)); |
| 2870 } | 2885 } |
| 2871 registry.registerTypeUse(new TypeUse.isCheck(type)); | 2886 registry.registerTypeUse(new TypeUse.isCheck(type)); |
| 2872 | 2887 |
| 2873 CheckedModeHelper helper; | 2888 CheckedModeHelper helper; |
| 2874 if (node.isBooleanConversionCheck) { | 2889 if (node.isBooleanConversionCheck) { |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2951 } | 2966 } |
| 2952 } | 2967 } |
| 2953 | 2968 |
| 2954 void visitTypeInfoReadRaw(HTypeInfoReadRaw node) { | 2969 void visitTypeInfoReadRaw(HTypeInfoReadRaw node) { |
| 2955 use(node.inputs[0]); | 2970 use(node.inputs[0]); |
| 2956 js.Expression receiver = pop(); | 2971 js.Expression receiver = pop(); |
| 2957 push(js.js(r'#.#', [receiver, backend.namer.rtiFieldName])); | 2972 push(js.js(r'#.#', [receiver, backend.namer.rtiFieldName])); |
| 2958 } | 2973 } |
| 2959 | 2974 |
| 2960 void visitTypeInfoReadVariable(HTypeInfoReadVariable node) { | 2975 void visitTypeInfoReadVariable(HTypeInfoReadVariable node) { |
| 2961 TypeVariableElement element = node.variable.element; | 2976 TypeVariableEntity element = node.variable.element; |
| 2962 | 2977 |
| 2963 int index = element.index; | 2978 int index = element.index; |
| 2964 HInstruction object = node.object; | 2979 HInstruction object = node.object; |
| 2965 use(object); | 2980 use(object); |
| 2966 js.Expression receiver = pop(); | 2981 js.Expression receiver = pop(); |
| 2967 | 2982 |
| 2968 if (typeVariableAccessNeedsSubstitution(element, object.instructionType)) { | 2983 if (typeVariableAccessNeedsSubstitution(element, object.instructionType)) { |
| 2969 js.Expression typeName = | 2984 js.Expression typeName = |
| 2970 js.quoteName(backend.namer.runtimeTypeName(element.enclosingClass)); | 2985 js.quoteName(backend.namer.runtimeTypeName(element.typeDeclaration)); |
| 2971 Element helperElement = helpers.getRuntimeTypeArgument; | 2986 FunctionEntity helperElement = helpers.getRuntimeTypeArgument; |
| 2972 registry.registerStaticUse( | 2987 registry.registerStaticUse( |
| 2973 new StaticUse.staticInvoke(helperElement, CallStructure.THREE_ARGS)); | 2988 new StaticUse.staticInvoke(helperElement, CallStructure.THREE_ARGS)); |
| 2974 js.Expression helper = | 2989 js.Expression helper = |
| 2975 backend.emitter.staticFunctionAccess(helperElement); | 2990 backend.emitter.staticFunctionAccess(helperElement); |
| 2976 push(js.js( | 2991 push(js.js( |
| 2977 r'#(#, #, #)', [helper, receiver, typeName, js.js.number(index)])); | 2992 r'#(#, #, #)', [helper, receiver, typeName, js.js.number(index)])); |
| 2978 } else { | 2993 } else { |
| 2979 Element helperElement = helpers.getTypeArgumentByIndex; | 2994 FunctionEntity helperElement = helpers.getTypeArgumentByIndex; |
| 2980 registry.registerStaticUse( | 2995 registry.registerStaticUse( |
| 2981 new StaticUse.staticInvoke(helperElement, CallStructure.TWO_ARGS)); | 2996 new StaticUse.staticInvoke(helperElement, CallStructure.TWO_ARGS)); |
| 2982 js.Expression helper = | 2997 js.Expression helper = |
| 2983 backend.emitter.staticFunctionAccess(helperElement); | 2998 backend.emitter.staticFunctionAccess(helperElement); |
| 2984 push(js.js(r'#(#, #)', [helper, receiver, js.js.number(index)])); | 2999 push(js.js(r'#(#, #)', [helper, receiver, js.js.number(index)])); |
| 2985 } | 3000 } |
| 2986 } | 3001 } |
| 2987 | 3002 |
| 2988 void visitTypeInfoExpression(HTypeInfoExpression node) { | 3003 void visitTypeInfoExpression(HTypeInfoExpression node) { |
| 2989 List<js.Expression> arguments = <js.Expression>[]; | 3004 List<js.Expression> arguments = <js.Expression>[]; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3005 // We expect only flat types for the INSTANCE representation. | 3020 // We expect only flat types for the INSTANCE representation. |
| 3006 assert( | 3021 assert( |
| 3007 node.dartType == (node.dartType as InterfaceType).element.thisType); | 3022 node.dartType == (node.dartType as InterfaceType).element.thisType); |
| 3008 registry.registerInstantiatedClass(commonElements.listClass); | 3023 registry.registerInstantiatedClass(commonElements.listClass); |
| 3009 push(new js.ArrayInitializer(arguments) | 3024 push(new js.ArrayInitializer(arguments) |
| 3010 .withSourceInformation(node.sourceInformation)); | 3025 .withSourceInformation(node.sourceInformation)); |
| 3011 } | 3026 } |
| 3012 } | 3027 } |
| 3013 | 3028 |
| 3014 bool typeVariableAccessNeedsSubstitution( | 3029 bool typeVariableAccessNeedsSubstitution( |
| 3015 TypeVariableElement element, TypeMask receiverMask) { | 3030 TypeVariableEntity element, TypeMask receiverMask) { |
| 3016 ClassElement cls = element.enclosingClass; | 3031 ClassEntity cls = element.typeDeclaration; |
| 3017 | 3032 |
| 3018 // See if the receiver type narrows the set of classes to ones that can be | 3033 // See if the receiver type narrows the set of classes to ones that can be |
| 3019 // indexed. | 3034 // indexed. |
| 3020 // TODO(sra): Currently the only convenient query is [singleClass]. We | 3035 // TODO(sra): Currently the only convenient query is [singleClass]. We |
| 3021 // should iterate over all the concrete classes in [receiverMask]. | 3036 // should iterate over all the concrete classes in [receiverMask]. |
| 3022 ClassElement receiverClass = receiverMask.singleClass(closedWorld); | 3037 ClassEntity receiverClass = receiverMask.singleClass(closedWorld); |
| 3023 if (receiverClass != null) { | 3038 if (receiverClass != null) { |
| 3024 if (backend.rti.isTrivialSubstitution(receiverClass, cls)) { | 3039 if (backend.rti.isTrivialSubstitution(receiverClass, cls)) { |
| 3025 return false; | 3040 return false; |
| 3026 } | 3041 } |
| 3027 } | 3042 } |
| 3028 | 3043 |
| 3029 if (closedWorld.isUsedAsMixin(cls)) return true; | 3044 if (closedWorld.isUsedAsMixin(cls)) return true; |
| 3030 | 3045 |
| 3031 return closedWorld.anyStrictSubclassOf(cls, (ClassElement subclass) { | 3046 return closedWorld.anyStrictSubclassOf(cls, (ClassEntity subclass) { |
| 3032 return !backend.rti.isTrivialSubstitution(subclass, cls); | 3047 return !backend.rti.isTrivialSubstitution(subclass, cls); |
| 3033 }); | 3048 }); |
| 3034 } | 3049 } |
| 3035 | 3050 |
| 3036 void visitReadTypeVariable(HReadTypeVariable node) { | 3051 void visitReadTypeVariable(HReadTypeVariable node) { |
| 3037 TypeVariableElement element = node.dartType.element; | 3052 TypeVariableEntity element = node.dartType.element; |
| 3038 Element helperElement = helpers.convertRtiToRuntimeType; | 3053 FunctionEntity helperElement = helpers.convertRtiToRuntimeType; |
| 3039 registry.registerStaticUse( | 3054 registry.registerStaticUse( |
| 3040 new StaticUse.staticInvoke(helperElement, CallStructure.ONE_ARG)); | 3055 new StaticUse.staticInvoke(helperElement, CallStructure.ONE_ARG)); |
| 3041 | 3056 |
| 3042 use(node.inputs[0]); | 3057 use(node.inputs[0]); |
| 3043 if (node.hasReceiver) { | 3058 if (node.hasReceiver) { |
| 3044 if (backend.isInterceptorClass(element.enclosingClass)) { | 3059 if (backend.isInterceptorClass(element.typeDeclaration)) { |
| 3045 int index = element.index; | 3060 int index = element.index; |
| 3046 js.Expression receiver = pop(); | 3061 js.Expression receiver = pop(); |
| 3047 js.Expression helper = | 3062 js.Expression helper = |
| 3048 backend.emitter.staticFunctionAccess(helperElement); | 3063 backend.emitter.staticFunctionAccess(helperElement); |
| 3049 js.Expression rtiFieldName = backend.namer.rtiFieldName; | 3064 js.Expression rtiFieldName = backend.namer.rtiFieldName; |
| 3050 push(js.js(r'#(#.# && #.#[#])', [ | 3065 push(js.js(r'#(#.# && #.#[#])', [ |
| 3051 helper, | 3066 helper, |
| 3052 receiver, | 3067 receiver, |
| 3053 rtiFieldName, | 3068 rtiFieldName, |
| 3054 receiver, | 3069 receiver, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 3066 } | 3081 } |
| 3067 } | 3082 } |
| 3068 | 3083 |
| 3069 void visitInterfaceType(HInterfaceType node) { | 3084 void visitInterfaceType(HInterfaceType node) { |
| 3070 List<js.Expression> typeArguments = <js.Expression>[]; | 3085 List<js.Expression> typeArguments = <js.Expression>[]; |
| 3071 for (HInstruction type in node.inputs) { | 3086 for (HInstruction type in node.inputs) { |
| 3072 use(type); | 3087 use(type); |
| 3073 typeArguments.add(pop()); | 3088 typeArguments.add(pop()); |
| 3074 } | 3089 } |
| 3075 InterfaceType type = node.dartType; | 3090 InterfaceType type = node.dartType; |
| 3076 ClassElement cls = type.element; | 3091 ClassEntity cls = type.element; |
| 3077 var arguments = [backend.emitter.typeAccess(cls)]; | 3092 var arguments = [backend.emitter.typeAccess(cls)]; |
| 3078 if (!typeArguments.isEmpty) { | 3093 if (!typeArguments.isEmpty) { |
| 3079 arguments.add(new js.ArrayInitializer(typeArguments)); | 3094 arguments.add(new js.ArrayInitializer(typeArguments)); |
| 3080 } | 3095 } |
| 3081 push(js.js('#(#)', [ | 3096 push(js.js('#(#)', [ |
| 3082 accessHelper(helpers.buildInterfaceType, arguments.length), | 3097 accessHelper(helpers.buildInterfaceType, arguments.length), |
| 3083 arguments | 3098 arguments |
| 3084 ])); | 3099 ])); |
| 3085 } | 3100 } |
| 3086 | 3101 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3101 registry.registerStaticUse(new StaticUse.staticInvoke( | 3116 registry.registerStaticUse(new StaticUse.staticInvoke( |
| 3102 helper, new CallStructure.unnamed(argumentCount))); | 3117 helper, new CallStructure.unnamed(argumentCount))); |
| 3103 return backend.emitter.staticFunctionAccess(helper); | 3118 return backend.emitter.staticFunctionAccess(helper); |
| 3104 } | 3119 } |
| 3105 | 3120 |
| 3106 @override | 3121 @override |
| 3107 void visitRef(HRef node) { | 3122 void visitRef(HRef node) { |
| 3108 visit(node.value); | 3123 visit(node.value); |
| 3109 } | 3124 } |
| 3110 } | 3125 } |
| OLD | NEW |