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 'dart:collection' show Queue; | 6 import 'dart:collection' show Queue; |
7 import '../common.dart'; | 7 import '../common.dart'; |
8 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; | 8 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
9 import '../common/tasks.dart' show CompilerTask; | 9 import '../common/tasks.dart' show CompilerTask; |
10 import '../constants/constant_system.dart'; | 10 import '../constants/constant_system.dart'; |
11 import '../constants/values.dart'; | 11 import '../constants/values.dart'; |
12 import '../common_elements.dart' show CommonElements; | 12 import '../common_elements.dart' show CommonElements; |
13 import '../elements/elements.dart' | 13 import '../elements/elements.dart' |
14 show AsyncMarker, JumpTarget, LabelDefinition, MethodElement, ResolvedAst; | 14 show AsyncMarker, JumpTarget, LabelDefinition, MethodElement, ResolvedAst; |
15 import '../elements/entities.dart'; | 15 import '../elements/entities.dart'; |
16 import '../elements/types.dart'; | 16 import '../elements/types.dart'; |
17 import '../io/source_information.dart'; | 17 import '../io/source_information.dart'; |
18 import '../js/js.dart' as js; | 18 import '../js/js.dart' as js; |
19 import '../js_backend/backend_helpers.dart' show BackendHelpers; | |
20 import '../js_backend/interceptor_data.dart'; | 19 import '../js_backend/interceptor_data.dart'; |
21 import '../js_backend/js_backend.dart'; | 20 import '../js_backend/js_backend.dart'; |
22 import '../js_backend/native_data.dart'; | 21 import '../js_backend/native_data.dart'; |
23 import '../js_emitter/code_emitter_task.dart'; | 22 import '../js_emitter/code_emitter_task.dart'; |
24 import '../native/native.dart' as native; | 23 import '../native/native.dart' as native; |
25 import '../options.dart'; | 24 import '../options.dart'; |
26 import '../types/types.dart'; | 25 import '../types/types.dart'; |
27 import '../universe/call_structure.dart' show CallStructure; | 26 import '../universe/call_structure.dart' show CallStructure; |
28 import '../universe/selector.dart' show Selector; | 27 import '../universe/selector.dart' show Selector; |
29 import '../universe/use.dart' show ConstantUse, DynamicUse, StaticUse, TypeUse; | 28 import '../universe/use.dart' show ConstantUse, DynamicUse, StaticUse, TypeUse; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 CodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) { | 72 CodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) { |
74 return measure(() { | 73 return measure(() { |
75 backend.tracer.traceGraph("codegen", graph); | 74 backend.tracer.traceGraph("codegen", graph); |
76 SourceInformation sourceInformation = sourceInformationFactory | 75 SourceInformation sourceInformation = sourceInformationFactory |
77 .createBuilderForContext(work.resolvedAst) | 76 .createBuilderForContext(work.resolvedAst) |
78 .buildDeclaration(work.resolvedAst); | 77 .buildDeclaration(work.resolvedAst); |
79 SsaCodeGenerator codegen = new SsaCodeGenerator( | 78 SsaCodeGenerator codegen = new SsaCodeGenerator( |
80 backend.compiler.options, | 79 backend.compiler.options, |
81 backend.emitter, | 80 backend.emitter, |
82 backend.nativeCodegenEnqueuer, | 81 backend.nativeCodegenEnqueuer, |
83 backend.helpers, | |
84 backend.checkedModeHelpers, | 82 backend.checkedModeHelpers, |
85 backend.nativeData, | 83 backend.nativeData, |
86 backend.interceptorData, | 84 backend.interceptorData, |
87 backend.oneShotInterceptorData, | 85 backend.oneShotInterceptorData, |
88 backend.rtiSubstitutions, | 86 backend.rtiSubstitutions, |
89 backend.rtiEncoder, | 87 backend.rtiEncoder, |
90 backend.namer, | 88 backend.namer, |
91 backend.superMemberData, | 89 backend.superMemberData, |
92 closedWorld, | 90 closedWorld, |
93 work); | 91 work); |
94 codegen.visitGraph(graph); | 92 codegen.visitGraph(graph); |
95 return new js.Fun(codegen.parameters, codegen.body) | 93 return new js.Fun(codegen.parameters, codegen.body) |
96 .withSourceInformation(sourceInformation); | 94 .withSourceInformation(sourceInformation); |
97 }); | 95 }); |
98 } | 96 } |
99 | 97 |
100 js.Expression generateMethod( | 98 js.Expression generateMethod( |
101 CodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) { | 99 CodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) { |
102 return measure(() { | 100 return measure(() { |
103 MethodElement element = work.element; | 101 MethodElement element = work.element; |
104 if (element.asyncMarker != AsyncMarker.SYNC) { | 102 if (element.asyncMarker != AsyncMarker.SYNC) { |
105 work.registry.registerAsyncMarker(element.asyncMarker); | 103 work.registry.registerAsyncMarker(element.asyncMarker); |
106 } | 104 } |
107 SsaCodeGenerator codegen = new SsaCodeGenerator( | 105 SsaCodeGenerator codegen = new SsaCodeGenerator( |
108 backend.compiler.options, | 106 backend.compiler.options, |
109 backend.emitter, | 107 backend.emitter, |
110 backend.nativeCodegenEnqueuer, | 108 backend.nativeCodegenEnqueuer, |
111 backend.helpers, | |
112 backend.checkedModeHelpers, | 109 backend.checkedModeHelpers, |
113 backend.nativeData, | 110 backend.nativeData, |
114 backend.interceptorData, | 111 backend.interceptorData, |
115 backend.oneShotInterceptorData, | 112 backend.oneShotInterceptorData, |
116 backend.rtiSubstitutions, | 113 backend.rtiSubstitutions, |
117 backend.rtiEncoder, | 114 backend.rtiEncoder, |
118 backend.namer, | 115 backend.namer, |
119 backend.superMemberData, | 116 backend.superMemberData, |
120 closedWorld, | 117 closedWorld, |
121 work); | 118 work); |
(...skipping 26 matching lines...) Expand all Loading... |
148 | 145 |
149 /** | 146 /** |
150 * Whether we are currently generating expressions instead of statements. | 147 * Whether we are currently generating expressions instead of statements. |
151 * This includes declarations, which are generated as expressions. | 148 * This includes declarations, which are generated as expressions. |
152 */ | 149 */ |
153 bool isGeneratingExpression = false; | 150 bool isGeneratingExpression = false; |
154 | 151 |
155 final CompilerOptions _options; | 152 final CompilerOptions _options; |
156 final CodeEmitterTask _emitter; | 153 final CodeEmitterTask _emitter; |
157 final native.NativeCodegenEnqueuer _nativeEnqueuer; | 154 final native.NativeCodegenEnqueuer _nativeEnqueuer; |
158 final BackendHelpers _helpers; | |
159 final CheckedModeHelpers _checkedModeHelpers; | 155 final CheckedModeHelpers _checkedModeHelpers; |
160 final NativeData _nativeData; | 156 final NativeData _nativeData; |
161 final InterceptorData _interceptorData; | 157 final InterceptorData _interceptorData; |
162 final OneShotInterceptorData _oneShotInterceptorData; | 158 final OneShotInterceptorData _oneShotInterceptorData; |
163 final RuntimeTypesSubstitutions _rtiSubstitutions; | 159 final RuntimeTypesSubstitutions _rtiSubstitutions; |
164 final RuntimeTypesEncoder _rtiEncoder; | 160 final RuntimeTypesEncoder _rtiEncoder; |
165 final Namer _namer; | 161 final Namer _namer; |
166 final SuperMemberData _superMemberData; | 162 final SuperMemberData _superMemberData; |
167 final ClosedWorld _closedWorld; | 163 final ClosedWorld _closedWorld; |
168 final CodegenWorkItem _work; | 164 final CodegenWorkItem _work; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 // if branches. | 203 // if branches. |
208 SubGraph subGraph; | 204 SubGraph subGraph; |
209 | 205 |
210 // Pending blocks than need to be visited as part of current subgraph. | 206 // Pending blocks than need to be visited as part of current subgraph. |
211 Queue<HBasicBlock> blockQueue; | 207 Queue<HBasicBlock> blockQueue; |
212 | 208 |
213 SsaCodeGenerator( | 209 SsaCodeGenerator( |
214 this._options, | 210 this._options, |
215 this._emitter, | 211 this._emitter, |
216 this._nativeEnqueuer, | 212 this._nativeEnqueuer, |
217 this._helpers, | |
218 this._checkedModeHelpers, | 213 this._checkedModeHelpers, |
219 this._nativeData, | 214 this._nativeData, |
220 this._interceptorData, | 215 this._interceptorData, |
221 this._oneShotInterceptorData, | 216 this._oneShotInterceptorData, |
222 this._rtiSubstitutions, | 217 this._rtiSubstitutions, |
223 this._rtiEncoder, | 218 this._rtiEncoder, |
224 this._namer, | 219 this._namer, |
225 this._superMemberData, | 220 this._superMemberData, |
226 this._closedWorld, | 221 this._closedWorld, |
227 this._work, | 222 this._work, |
(...skipping 612 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
840 js.Block body = generateStatementsInNewBlock(info.body); | 835 js.Block body = generateStatementsInNewBlock(info.body); |
841 js.Catch catchPart = null; | 836 js.Catch catchPart = null; |
842 js.Block finallyPart = null; | 837 js.Block finallyPart = null; |
843 if (info.catchBlock != null) { | 838 if (info.catchBlock != null) { |
844 void register(ClassEntity classElement) { | 839 void register(ClassEntity classElement) { |
845 if (classElement != null) { | 840 if (classElement != null) { |
846 _registry.registerInstantiatedClass(classElement); | 841 _registry.registerInstantiatedClass(classElement); |
847 } | 842 } |
848 } | 843 } |
849 | 844 |
850 register(_helpers.jsPlainJavaScriptObjectClass); | 845 register(_commonElements.jsPlainJavaScriptObjectClass); |
851 register(_helpers.jsUnknownJavaScriptObjectClass); | 846 register(_commonElements.jsUnknownJavaScriptObjectClass); |
852 | 847 |
853 HLocalValue exception = info.catchVariable; | 848 HLocalValue exception = info.catchVariable; |
854 String name = variableNames.getName(exception); | 849 String name = variableNames.getName(exception); |
855 js.VariableDeclaration decl = new js.VariableDeclaration(name); | 850 js.VariableDeclaration decl = new js.VariableDeclaration(name); |
856 js.Block catchBlock = generateStatementsInNewBlock(info.catchBlock); | 851 js.Block catchBlock = generateStatementsInNewBlock(info.catchBlock); |
857 catchPart = new js.Catch(decl, catchBlock); | 852 catchPart = new js.Catch(decl, catchBlock); |
858 } | 853 } |
859 if (info.finallyBlock != null) { | 854 if (info.finallyBlock != null) { |
860 finallyPart = generateStatementsInNewBlock(info.finallyBlock); | 855 finallyPart = generateStatementsInNewBlock(info.finallyBlock); |
861 } | 856 } |
(...skipping 821 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1683 use(node.receiver); | 1678 use(node.receiver); |
1684 js.Expression receiverExpression = pop(); | 1679 js.Expression receiverExpression = pop(); |
1685 use(node.conditionalConstantInterceptor); | 1680 use(node.conditionalConstantInterceptor); |
1686 js.Expression constant = pop(); | 1681 js.Expression constant = pop(); |
1687 push(js.js('# && #', [receiverExpression, constant])); | 1682 push(js.js('# && #', [receiverExpression, constant])); |
1688 } else { | 1683 } else { |
1689 assert(node.inputs.length == 1); | 1684 assert(node.inputs.length == 1); |
1690 _registry.registerSpecializedGetInterceptor(node.interceptedClasses); | 1685 _registry.registerSpecializedGetInterceptor(node.interceptedClasses); |
1691 js.Name name = _namer.nameForGetInterceptor(node.interceptedClasses); | 1686 js.Name name = _namer.nameForGetInterceptor(node.interceptedClasses); |
1692 var isolate = new js.VariableUse( | 1687 var isolate = new js.VariableUse( |
1693 _namer.globalObjectForLibrary(_helpers.interceptorsLibrary)); | 1688 _namer.globalObjectForLibrary(_commonElements.interceptorsLibrary)); |
1694 use(node.receiver); | 1689 use(node.receiver); |
1695 List<js.Expression> arguments = <js.Expression>[pop()]; | 1690 List<js.Expression> arguments = <js.Expression>[pop()]; |
1696 push(js | 1691 push(js |
1697 .propertyCall(isolate, name, arguments) | 1692 .propertyCall(isolate, name, arguments) |
1698 .withSourceInformation(node.sourceInformation)); | 1693 .withSourceInformation(node.sourceInformation)); |
1699 _registry.registerUseInterceptor(); | 1694 _registry.registerUseInterceptor(); |
1700 } | 1695 } |
1701 } | 1696 } |
1702 | 1697 |
1703 visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 1698 visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
1704 use(node.receiver); | 1699 use(node.receiver); |
1705 js.Expression object = pop(); | 1700 js.Expression object = pop(); |
1706 String methodName; | 1701 String methodName; |
1707 List<js.Expression> arguments = visitArguments(node.inputs); | 1702 List<js.Expression> arguments = visitArguments(node.inputs); |
1708 MemberEntity target = node.element; | 1703 MemberEntity target = node.element; |
1709 | 1704 |
1710 // TODO(herhut): The namer should return the appropriate backendname here. | 1705 // TODO(herhut): The namer should return the appropriate backendname here. |
1711 if (target != null && !node.isInterceptedCall) { | 1706 if (target != null && !node.isInterceptedCall) { |
1712 if (target == _helpers.jsArrayAdd) { | 1707 if (target == _commonElements.jsArrayAdd) { |
1713 methodName = 'push'; | 1708 methodName = 'push'; |
1714 } else if (target == _helpers.jsArrayRemoveLast) { | 1709 } else if (target == _commonElements.jsArrayRemoveLast) { |
1715 methodName = 'pop'; | 1710 methodName = 'pop'; |
1716 } else if (target == _helpers.jsStringSplit) { | 1711 } else if (target == _commonElements.jsStringSplit) { |
1717 methodName = 'split'; | 1712 methodName = 'split'; |
1718 // Split returns a List, so we make sure the backend knows the | 1713 // Split returns a List, so we make sure the backend knows the |
1719 // list class is instantiated. | 1714 // list class is instantiated. |
1720 _registry.registerInstantiatedClass(_commonElements.listClass); | 1715 _registry.registerInstantiatedClass(_commonElements.listClass); |
1721 } else if (_nativeData.isNativeMember(target) && | 1716 } else if (_nativeData.isNativeMember(target) && |
1722 target.isFunction && | 1717 target.isFunction && |
1723 !node.isInterceptedCall) { | 1718 !node.isInterceptedCall) { |
1724 // A direct (i.e. non-interceptor) native call is the result of | 1719 // A direct (i.e. non-interceptor) native call is the result of |
1725 // optimization. The optimization ensures any type checks or | 1720 // optimization. The optimization ensures any type checks or |
1726 // conversions have been satisified. | 1721 // conversions have been satisified. |
(...skipping 21 matching lines...) Expand all Loading... |
1748 push(js | 1743 push(js |
1749 .propertyCall(object, methodName, arguments) | 1744 .propertyCall(object, methodName, arguments) |
1750 .withSourceInformation(node.sourceInformation)); | 1745 .withSourceInformation(node.sourceInformation)); |
1751 _registry.registerStaticUse(new StaticUse.constructorBodyInvoke( | 1746 _registry.registerStaticUse(new StaticUse.constructorBodyInvoke( |
1752 node.element, new CallStructure.unnamed(arguments.length))); | 1747 node.element, new CallStructure.unnamed(arguments.length))); |
1753 } | 1748 } |
1754 | 1749 |
1755 void visitOneShotInterceptor(HOneShotInterceptor node) { | 1750 void visitOneShotInterceptor(HOneShotInterceptor node) { |
1756 List<js.Expression> arguments = visitArguments(node.inputs); | 1751 List<js.Expression> arguments = visitArguments(node.inputs); |
1757 var isolate = new js.VariableUse( | 1752 var isolate = new js.VariableUse( |
1758 _namer.globalObjectForLibrary(_helpers.interceptorsLibrary)); | 1753 _namer.globalObjectForLibrary(_commonElements.interceptorsLibrary)); |
1759 Selector selector = node.selector; | 1754 Selector selector = node.selector; |
1760 js.Name methodName = | 1755 js.Name methodName = |
1761 _oneShotInterceptorData.registerOneShotInterceptor(selector, _namer); | 1756 _oneShotInterceptorData.registerOneShotInterceptor(selector, _namer); |
1762 push(js | 1757 push(js |
1763 .propertyCall(isolate, methodName, arguments) | 1758 .propertyCall(isolate, methodName, arguments) |
1764 .withSourceInformation(node.sourceInformation)); | 1759 .withSourceInformation(node.sourceInformation)); |
1765 if (selector.isGetter) { | 1760 if (selector.isGetter) { |
1766 registerGetter(node); | 1761 registerGetter(node); |
1767 } else if (selector.isSetter) { | 1762 } else if (selector.isSetter) { |
1768 registerSetter(node); | 1763 registerSetter(node); |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1888 List<DartType> instantiatedTypes = node.instantiatedTypes; | 1883 List<DartType> instantiatedTypes = node.instantiatedTypes; |
1889 | 1884 |
1890 if (instantiatedTypes != null && !instantiatedTypes.isEmpty) { | 1885 if (instantiatedTypes != null && !instantiatedTypes.isEmpty) { |
1891 instantiatedTypes.forEach((type) { | 1886 instantiatedTypes.forEach((type) { |
1892 _registry.registerInstantiation(type); | 1887 _registry.registerInstantiation(type); |
1893 }); | 1888 }); |
1894 } | 1889 } |
1895 | 1890 |
1896 List<js.Expression> arguments = visitArguments(node.inputs, start: 0); | 1891 List<js.Expression> arguments = visitArguments(node.inputs, start: 0); |
1897 | 1892 |
1898 if (element == _helpers.checkConcurrentModificationError) { | 1893 if (element == _commonElements.checkConcurrentModificationError) { |
1899 // Manually inline the [checkConcurrentModificationError] function. This | 1894 // Manually inline the [checkConcurrentModificationError] function. This |
1900 // function is only called from a for-loop update. Ideally we would just | 1895 // function is only called from a for-loop update. Ideally we would just |
1901 // generate the conditionalcontrol flow in the builder but it adds basic | 1896 // generate the conditionalcontrol flow in the builder but it adds basic |
1902 // blocks in the loop update that interfere with other optimizations and | 1897 // blocks in the loop update that interfere with other optimizations and |
1903 // confuses loop recognition. | 1898 // confuses loop recognition. |
1904 | 1899 |
1905 assert(arguments.length == 2); | 1900 assert(arguments.length == 2); |
1906 FunctionEntity throwFunction = _helpers.throwConcurrentModificationError; | 1901 FunctionEntity throwFunction = |
| 1902 _commonElements.throwConcurrentModificationError; |
1907 _registry.registerStaticUse( | 1903 _registry.registerStaticUse( |
1908 new StaticUse.staticInvoke(throwFunction, CallStructure.ONE_ARG)); | 1904 new StaticUse.staticInvoke(throwFunction, CallStructure.ONE_ARG)); |
1909 | 1905 |
1910 // Calling using `(0, #)(#)` instead of `#(#)` separates the property load | 1906 // Calling using `(0, #)(#)` instead of `#(#)` separates the property load |
1911 // of the static function access from the call. For some reason this | 1907 // of the static function access from the call. For some reason this |
1912 // helps V8 see that the call never happens so V8 makes the call a | 1908 // helps V8 see that the call never happens so V8 makes the call a |
1913 // deoptimization. This removes the call from the optimized loop, making | 1909 // deoptimization. This removes the call from the optimized loop, making |
1914 // more optimizations available to the loop. This form is 50% faster on | 1910 // more optimizations available to the loop. This form is 50% faster on |
1915 // some small loop, almost as fast as loops with no concurrent | 1911 // some small loop, almost as fast as loops with no concurrent |
1916 // modification check. | 1912 // modification check. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1951 } | 1947 } |
1952 } else { | 1948 } else { |
1953 Selector selector = node.selector; | 1949 Selector selector = node.selector; |
1954 if (!_superMemberData.maybeRegisterAliasedSuperMember( | 1950 if (!_superMemberData.maybeRegisterAliasedSuperMember( |
1955 superElement, selector)) { | 1951 superElement, selector)) { |
1956 js.Name methodName; | 1952 js.Name methodName; |
1957 if (selector.isGetter && !superElement.isGetter) { | 1953 if (selector.isGetter && !superElement.isGetter) { |
1958 // If this is a tear-off, register the fact that a tear-off closure | 1954 // If this is a tear-off, register the fact that a tear-off closure |
1959 // will be created, and that this tear-off must bypass ordinary | 1955 // will be created, and that this tear-off must bypass ordinary |
1960 // dispatch to ensure the super method is invoked. | 1956 // dispatch to ensure the super method is invoked. |
1961 FunctionEntity helper = _helpers.closureFromTearOff; | 1957 FunctionEntity helper = _commonElements.closureFromTearOff; |
1962 _registry.registerStaticUse(new StaticUse.staticInvoke( | 1958 _registry.registerStaticUse(new StaticUse.staticInvoke( |
1963 helper, new CallStructure.unnamed(node.inputs.length))); | 1959 helper, new CallStructure.unnamed(node.inputs.length))); |
1964 _registry.registerStaticUse(new StaticUse.superTearOff(node.element)); | 1960 _registry.registerStaticUse(new StaticUse.superTearOff(node.element)); |
1965 methodName = _namer.invocationName(selector); | 1961 methodName = _namer.invocationName(selector); |
1966 } else { | 1962 } else { |
1967 methodName = _namer.instanceMethodName(superElement); | 1963 methodName = _namer.instanceMethodName(superElement); |
1968 } | 1964 } |
1969 _registry.registerStaticUse(new StaticUse.superInvoke( | 1965 _registry.registerStaticUse(new StaticUse.superInvoke( |
1970 superElement, new CallStructure.unnamed(node.inputs.length))); | 1966 superElement, new CallStructure.unnamed(node.inputs.length))); |
1971 push(js.js('#.#.call(#)', [ | 1967 push(js.js('#.#.call(#)', [ |
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2266 visitThis(HThis node) { | 2262 visitThis(HThis node) { |
2267 push(new js.This()); | 2263 push(new js.This()); |
2268 } | 2264 } |
2269 | 2265 |
2270 visitThrow(HThrow node) { | 2266 visitThrow(HThrow node) { |
2271 if (node.isRethrow) { | 2267 if (node.isRethrow) { |
2272 use(node.inputs[0]); | 2268 use(node.inputs[0]); |
2273 pushStatement( | 2269 pushStatement( |
2274 new js.Throw(pop()).withSourceInformation(node.sourceInformation)); | 2270 new js.Throw(pop()).withSourceInformation(node.sourceInformation)); |
2275 } else { | 2271 } else { |
2276 generateThrowWithHelper(_helpers.wrapExceptionHelper, node.inputs[0], | 2272 generateThrowWithHelper( |
| 2273 _commonElements.wrapExceptionHelper, node.inputs[0], |
2277 sourceInformation: node.sourceInformation); | 2274 sourceInformation: node.sourceInformation); |
2278 } | 2275 } |
2279 } | 2276 } |
2280 | 2277 |
2281 visitAwait(HAwait node) { | 2278 visitAwait(HAwait node) { |
2282 use(node.inputs[0]); | 2279 use(node.inputs[0]); |
2283 push(new js.Await(pop()).withSourceInformation(node.sourceInformation)); | 2280 push(new js.Await(pop()).withSourceInformation(node.sourceInformation)); |
2284 } | 2281 } |
2285 | 2282 |
2286 visitYield(HYield node) { | 2283 visitYield(HYield node) { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2324 use(node.length); | 2321 use(node.length); |
2325 over = new js.Binary(">=", jsIndex, pop()); | 2322 over = new js.Binary(">=", jsIndex, pop()); |
2326 } | 2323 } |
2327 assert(over != null || under != null); | 2324 assert(over != null || under != null); |
2328 js.Expression underOver = under == null | 2325 js.Expression underOver = under == null |
2329 ? over | 2326 ? over |
2330 : over == null ? under : new js.Binary("||", under, over); | 2327 : over == null ? under : new js.Binary("||", under, over); |
2331 js.Statement thenBody = new js.Block.empty(); | 2328 js.Statement thenBody = new js.Block.empty(); |
2332 js.Block oldContainer = currentContainer; | 2329 js.Block oldContainer = currentContainer; |
2333 currentContainer = thenBody; | 2330 currentContainer = thenBody; |
2334 generateThrowWithHelper(_helpers.throwIndexOutOfRangeException, | 2331 generateThrowWithHelper(_commonElements.throwIndexOutOfRangeException, |
2335 [node.array, node.reportedIndex]); | 2332 [node.array, node.reportedIndex]); |
2336 currentContainer = oldContainer; | 2333 currentContainer = oldContainer; |
2337 thenBody = unwrapStatement(thenBody); | 2334 thenBody = unwrapStatement(thenBody); |
2338 pushStatement(new js.If.noElse(underOver, thenBody) | 2335 pushStatement(new js.If.noElse(underOver, thenBody) |
2339 .withSourceInformation(node.sourceInformation)); | 2336 .withSourceInformation(node.sourceInformation)); |
2340 } else { | 2337 } else { |
2341 generateThrowWithHelper( | 2338 generateThrowWithHelper(_commonElements.throwIndexOutOfRangeException, |
2342 _helpers.throwIndexOutOfRangeException, [node.array, node.index]); | 2339 [node.array, node.index]); |
2343 } | 2340 } |
2344 } | 2341 } |
2345 | 2342 |
2346 void generateThrowWithHelper(FunctionEntity helper, argument, | 2343 void generateThrowWithHelper(FunctionEntity helper, argument, |
2347 {SourceInformation sourceInformation}) { | 2344 {SourceInformation sourceInformation}) { |
2348 js.Expression jsHelper = _emitter.staticFunctionAccess(helper); | 2345 js.Expression jsHelper = _emitter.staticFunctionAccess(helper); |
2349 List arguments = []; | 2346 List arguments = []; |
2350 if (argument is List) { | 2347 if (argument is List) { |
2351 argument.forEach((instruction) { | 2348 argument.forEach((instruction) { |
2352 use(instruction); | 2349 use(instruction); |
2353 arguments.add(pop()); | 2350 arguments.add(pop()); |
2354 }); | 2351 }); |
2355 } else { | 2352 } else { |
2356 use(argument); | 2353 use(argument); |
2357 arguments.add(pop()); | 2354 arguments.add(pop()); |
2358 } | 2355 } |
2359 _registry.registerStaticUse(new StaticUse.staticInvoke( | 2356 _registry.registerStaticUse(new StaticUse.staticInvoke( |
2360 helper, new CallStructure.unnamed(arguments.length))); | 2357 helper, new CallStructure.unnamed(arguments.length))); |
2361 js.Call value = new js.Call(jsHelper, arguments.toList(growable: false), | 2358 js.Call value = new js.Call(jsHelper, arguments.toList(growable: false), |
2362 sourceInformation: sourceInformation); | 2359 sourceInformation: sourceInformation); |
2363 // BUG(4906): Using throw/return here adds to the size of the generated code | 2360 // BUG(4906): Using throw/return here adds to the size of the generated code |
2364 // but it has the advantage of explicitly telling the JS engine that | 2361 // but it has the advantage of explicitly telling the JS engine that |
2365 // this code path will terminate abruptly. Needs more work. | 2362 // this code path will terminate abruptly. Needs more work. |
2366 if (helper == _helpers.wrapExceptionHelper) { | 2363 if (helper == _commonElements.wrapExceptionHelper) { |
2367 pushStatement( | 2364 pushStatement( |
2368 new js.Throw(value).withSourceInformation(sourceInformation)); | 2365 new js.Throw(value).withSourceInformation(sourceInformation)); |
2369 } else { | 2366 } else { |
2370 Entity element = _work.element; | 2367 Entity element = _work.element; |
2371 if (element is MethodElement && element.asyncMarker.isYielding) { | 2368 if (element is MethodElement && element.asyncMarker.isYielding) { |
2372 // `return <expr>;` is illegal in a sync* or async* function. | 2369 // `return <expr>;` is illegal in a sync* or async* function. |
2373 // To have the async-translator working, we avoid introducing | 2370 // To have the async-translator working, we avoid introducing |
2374 // `return` nodes. | 2371 // `return` nodes. |
2375 pushStatement(new js.ExpressionStatement(value) | 2372 pushStatement(new js.ExpressionStatement(value) |
2376 .withSourceInformation(sourceInformation)); | 2373 .withSourceInformation(sourceInformation)); |
2377 } else { | 2374 } else { |
2378 pushStatement( | 2375 pushStatement( |
2379 new js.Return(value).withSourceInformation(sourceInformation)); | 2376 new js.Return(value).withSourceInformation(sourceInformation)); |
2380 } | 2377 } |
2381 } | 2378 } |
2382 } | 2379 } |
2383 | 2380 |
2384 visitThrowExpression(HThrowExpression node) { | 2381 visitThrowExpression(HThrowExpression node) { |
2385 HInstruction argument = node.inputs[0]; | 2382 HInstruction argument = node.inputs[0]; |
2386 use(argument); | 2383 use(argument); |
2387 | 2384 |
2388 FunctionEntity helper = _helpers.throwExpressionHelper; | 2385 FunctionEntity helper = _commonElements.throwExpressionHelper; |
2389 _registry.registerStaticUse( | 2386 _registry.registerStaticUse( |
2390 new StaticUse.staticInvoke(helper, CallStructure.ONE_ARG)); | 2387 new StaticUse.staticInvoke(helper, CallStructure.ONE_ARG)); |
2391 | 2388 |
2392 js.Expression jsHelper = _emitter.staticFunctionAccess(helper); | 2389 js.Expression jsHelper = _emitter.staticFunctionAccess(helper); |
2393 js.Call value = new js.Call(jsHelper, [pop()]) | 2390 js.Call value = new js.Call(jsHelper, [pop()]) |
2394 .withSourceInformation(node.sourceInformation); | 2391 .withSourceInformation(node.sourceInformation); |
2395 push(value); | 2392 push(value); |
2396 } | 2393 } |
2397 | 2394 |
2398 void visitSwitch(HSwitch node) { | 2395 void visitSwitch(HSwitch node) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2451 if (node.usedBy.length == 1 && | 2448 if (node.usedBy.length == 1 && |
2452 node.usedBy[0] is HStringConcat && | 2449 node.usedBy[0] is HStringConcat && |
2453 node.usedBy[0].inputs[1] == node) { | 2450 node.usedBy[0].inputs[1] == node) { |
2454 // The context is already <string> + value. | 2451 // The context is already <string> + value. |
2455 } else { | 2452 } else { |
2456 // Force an empty string for the first operand. | 2453 // Force an empty string for the first operand. |
2457 push(new js.Binary('+', js.string(""), pop()) | 2454 push(new js.Binary('+', js.string(""), pop()) |
2458 .withSourceInformation(node.sourceInformation)); | 2455 .withSourceInformation(node.sourceInformation)); |
2459 } | 2456 } |
2460 } else { | 2457 } else { |
2461 FunctionEntity convertToString = _helpers.stringInterpolationHelper; | 2458 FunctionEntity convertToString = |
| 2459 _commonElements.stringInterpolationHelper; |
2462 _registry.registerStaticUse( | 2460 _registry.registerStaticUse( |
2463 new StaticUse.staticInvoke(convertToString, CallStructure.ONE_ARG)); | 2461 new StaticUse.staticInvoke(convertToString, CallStructure.ONE_ARG)); |
2464 js.Expression jsHelper = _emitter.staticFunctionAccess(convertToString); | 2462 js.Expression jsHelper = _emitter.staticFunctionAccess(convertToString); |
2465 use(input); | 2463 use(input); |
2466 push(new js.Call(jsHelper, <js.Expression>[pop()], | 2464 push(new js.Call(jsHelper, <js.Expression>[pop()], |
2467 sourceInformation: node.sourceInformation)); | 2465 sourceInformation: node.sourceInformation)); |
2468 } | 2466 } |
2469 } | 2467 } |
2470 | 2468 |
2471 void visitLiteralList(HLiteralList node) { | 2469 void visitLiteralList(HLiteralList node) { |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2612 use(input); | 2610 use(input); |
2613 push(new js.Binary('!=', pop(), new js.LiteralNull())); | 2611 push(new js.Binary('!=', pop(), new js.LiteralNull())); |
2614 } | 2612 } |
2615 | 2613 |
2616 void checkType(HInstruction input, HInstruction interceptor, DartType type, | 2614 void checkType(HInstruction input, HInstruction interceptor, DartType type, |
2617 SourceInformation sourceInformation, | 2615 SourceInformation sourceInformation, |
2618 {bool negative: false}) { | 2616 {bool negative: false}) { |
2619 if (type.isInterfaceType) { | 2617 if (type.isInterfaceType) { |
2620 InterfaceType interfaceType = type; | 2618 InterfaceType interfaceType = type; |
2621 ClassEntity element = interfaceType.element; | 2619 ClassEntity element = interfaceType.element; |
2622 if (element == _helpers.jsArrayClass) { | 2620 if (element == _commonElements.jsArrayClass) { |
2623 checkArray(input, negative ? '!==' : '==='); | 2621 checkArray(input, negative ? '!==' : '==='); |
2624 return; | 2622 return; |
2625 } else if (element == _helpers.jsMutableArrayClass) { | 2623 } else if (element == _commonElements.jsMutableArrayClass) { |
2626 if (negative) { | 2624 if (negative) { |
2627 checkImmutableArray(input); | 2625 checkImmutableArray(input); |
2628 } else { | 2626 } else { |
2629 checkMutableArray(input); | 2627 checkMutableArray(input); |
2630 } | 2628 } |
2631 return; | 2629 return; |
2632 } else if (element == _helpers.jsExtendableArrayClass) { | 2630 } else if (element == _commonElements.jsExtendableArrayClass) { |
2633 if (negative) { | 2631 if (negative) { |
2634 checkFixedArray(input); | 2632 checkFixedArray(input); |
2635 } else { | 2633 } else { |
2636 checkExtendableArray(input); | 2634 checkExtendableArray(input); |
2637 } | 2635 } |
2638 return; | 2636 return; |
2639 } else if (element == _helpers.jsFixedArrayClass) { | 2637 } else if (element == _commonElements.jsFixedArrayClass) { |
2640 if (negative) { | 2638 if (negative) { |
2641 checkExtendableArray(input); | 2639 checkExtendableArray(input); |
2642 } else { | 2640 } else { |
2643 checkFixedArray(input); | 2641 checkFixedArray(input); |
2644 } | 2642 } |
2645 return; | 2643 return; |
2646 } else if (element == _helpers.jsUnmodifiableArrayClass) { | 2644 } else if (element == _commonElements.jsUnmodifiableArrayClass) { |
2647 if (negative) { | 2645 if (negative) { |
2648 checkMutableArray(input); | 2646 checkMutableArray(input); |
2649 } else { | 2647 } else { |
2650 checkImmutableArray(input); | 2648 checkImmutableArray(input); |
2651 } | 2649 } |
2652 return; | 2650 return; |
2653 } | 2651 } |
2654 } | 2652 } |
2655 if (interceptor != null) { | 2653 if (interceptor != null) { |
2656 checkTypeViaProperty(interceptor, type, sourceInformation, | 2654 checkTypeViaProperty(interceptor, type, sourceInformation, |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2860 // Figure out if it is beneficial to turn this into a null check. | 2858 // Figure out if it is beneficial to turn this into a null check. |
2861 // V8 generally prefers 'typeof' checks, but for integers and | 2859 // V8 generally prefers 'typeof' checks, but for integers and |
2862 // indexable primitives we cannot compile this test into a single | 2860 // indexable primitives we cannot compile this test into a single |
2863 // typeof check so the null check is cheaper. | 2861 // typeof check so the null check is cheaper. |
2864 bool isIntCheck = checkedType.containsOnlyInt(_closedWorld); | 2862 bool isIntCheck = checkedType.containsOnlyInt(_closedWorld); |
2865 bool turnIntoNumCheck = | 2863 bool turnIntoNumCheck = |
2866 isIntCheck && inputType.containsOnlyInt(_closedWorld); | 2864 isIntCheck && inputType.containsOnlyInt(_closedWorld); |
2867 bool turnIntoNullCheck = !turnIntoNumCheck && | 2865 bool turnIntoNullCheck = !turnIntoNumCheck && |
2868 (checkedType.nullable() == inputType) && | 2866 (checkedType.nullable() == inputType) && |
2869 (isIntCheck || | 2867 (isIntCheck || |
2870 checkedType.satisfies(_helpers.jsIndexableClass, _closedWorld)); | 2868 checkedType.satisfies( |
| 2869 _commonElements.jsIndexableClass, _closedWorld)); |
2871 | 2870 |
2872 if (turnIntoNullCheck) { | 2871 if (turnIntoNullCheck) { |
2873 use(input); | 2872 use(input); |
2874 return new js.Binary("==", pop(), new js.LiteralNull()) | 2873 return new js.Binary("==", pop(), new js.LiteralNull()) |
2875 .withSourceInformation(input.sourceInformation); | 2874 .withSourceInformation(input.sourceInformation); |
2876 } else if (isIntCheck && !turnIntoNumCheck) { | 2875 } else if (isIntCheck && !turnIntoNumCheck) { |
2877 // input is !int | 2876 // input is !int |
2878 checkBigInt(input, '!==', input.sourceInformation); | 2877 checkBigInt(input, '!==', input.sourceInformation); |
2879 return pop(); | 2878 return pop(); |
2880 } else if (turnIntoNumCheck || checkedType.containsOnlyNum(_closedWorld)) { | 2879 } else if (turnIntoNumCheck || checkedType.containsOnlyNum(_closedWorld)) { |
(...skipping 14 matching lines...) Expand all Loading... |
2895 } | 2894 } |
2896 | 2895 |
2897 void visitTypeConversion(HTypeConversion node) { | 2896 void visitTypeConversion(HTypeConversion node) { |
2898 if (node.isArgumentTypeCheck || node.isReceiverTypeCheck) { | 2897 if (node.isArgumentTypeCheck || node.isReceiverTypeCheck) { |
2899 js.Expression test = generateReceiverOrArgumentTypeTest(node); | 2898 js.Expression test = generateReceiverOrArgumentTypeTest(node); |
2900 js.Block oldContainer = currentContainer; | 2899 js.Block oldContainer = currentContainer; |
2901 js.Statement body = new js.Block.empty(); | 2900 js.Statement body = new js.Block.empty(); |
2902 currentContainer = body; | 2901 currentContainer = body; |
2903 if (node.isArgumentTypeCheck) { | 2902 if (node.isArgumentTypeCheck) { |
2904 generateThrowWithHelper( | 2903 generateThrowWithHelper( |
2905 _helpers.throwIllegalArgumentException, node.checkedInput, | 2904 _commonElements.throwIllegalArgumentException, node.checkedInput, |
2906 sourceInformation: node.sourceInformation); | 2905 sourceInformation: node.sourceInformation); |
2907 } else if (node.isReceiverTypeCheck) { | 2906 } else if (node.isReceiverTypeCheck) { |
2908 use(node.checkedInput); | 2907 use(node.checkedInput); |
2909 js.Name methodName = | 2908 js.Name methodName = |
2910 _namer.invocationName(node.receiverTypeCheckSelector); | 2909 _namer.invocationName(node.receiverTypeCheckSelector); |
2911 js.Expression call = js.propertyCall(pop(), methodName, []); | 2910 js.Expression call = js.propertyCall(pop(), methodName, []); |
2912 pushStatement(new js.Return(call)); | 2911 pushStatement(new js.Return(call)); |
2913 } | 2912 } |
2914 currentContainer = oldContainer; | 2913 currentContainer = oldContainer; |
2915 body = unwrapStatement(body); | 2914 body = unwrapStatement(body); |
(...skipping 15 matching lines...) Expand all Loading... |
2931 _registry.registerTypeUse(new TypeUse.isCheck(type)); | 2930 _registry.registerTypeUse(new TypeUse.isCheck(type)); |
2932 | 2931 |
2933 CheckedModeHelper helper; | 2932 CheckedModeHelper helper; |
2934 if (node.isBooleanConversionCheck) { | 2933 if (node.isBooleanConversionCheck) { |
2935 helper = const CheckedModeHelper('boolConversionCheck'); | 2934 helper = const CheckedModeHelper('boolConversionCheck'); |
2936 } else { | 2935 } else { |
2937 helper = _checkedModeHelpers.getCheckedModeHelper(type, | 2936 helper = _checkedModeHelpers.getCheckedModeHelper(type, |
2938 typeCast: node.isCastTypeCheck); | 2937 typeCast: node.isCastTypeCheck); |
2939 } | 2938 } |
2940 | 2939 |
2941 StaticUse staticUse = helper.getStaticUse(_helpers); | 2940 StaticUse staticUse = helper.getStaticUse(_commonElements); |
2942 _registry.registerStaticUse(staticUse); | 2941 _registry.registerStaticUse(staticUse); |
2943 List<js.Expression> arguments = <js.Expression>[]; | 2942 List<js.Expression> arguments = <js.Expression>[]; |
2944 use(node.checkedInput); | 2943 use(node.checkedInput); |
2945 arguments.add(pop()); | 2944 arguments.add(pop()); |
2946 helper.generateAdditionalArguments(this, _namer, node, arguments); | 2945 helper.generateAdditionalArguments(this, _namer, node, arguments); |
2947 push(new js.Call( | 2946 push(new js.Call( |
2948 _emitter.staticFunctionAccess(staticUse.element), arguments)); | 2947 _emitter.staticFunctionAccess(staticUse.element), arguments)); |
2949 } | 2948 } |
2950 | 2949 |
2951 void visitTypeKnown(HTypeKnown node) { | 2950 void visitTypeKnown(HTypeKnown node) { |
(...skipping 11 matching lines...) Expand all Loading... |
2963 TypeVariableEntity element = node.variable.element; | 2962 TypeVariableEntity element = node.variable.element; |
2964 | 2963 |
2965 int index = element.index; | 2964 int index = element.index; |
2966 HInstruction object = node.object; | 2965 HInstruction object = node.object; |
2967 use(object); | 2966 use(object); |
2968 js.Expression receiver = pop(); | 2967 js.Expression receiver = pop(); |
2969 | 2968 |
2970 if (typeVariableAccessNeedsSubstitution(element, object.instructionType)) { | 2969 if (typeVariableAccessNeedsSubstitution(element, object.instructionType)) { |
2971 js.Expression typeName = | 2970 js.Expression typeName = |
2972 js.quoteName(_namer.runtimeTypeName(element.typeDeclaration)); | 2971 js.quoteName(_namer.runtimeTypeName(element.typeDeclaration)); |
2973 FunctionEntity helperElement = _helpers.getRuntimeTypeArgument; | 2972 FunctionEntity helperElement = _commonElements.getRuntimeTypeArgument; |
2974 _registry.registerStaticUse( | 2973 _registry.registerStaticUse( |
2975 new StaticUse.staticInvoke(helperElement, CallStructure.THREE_ARGS)); | 2974 new StaticUse.staticInvoke(helperElement, CallStructure.THREE_ARGS)); |
2976 js.Expression helper = _emitter.staticFunctionAccess(helperElement); | 2975 js.Expression helper = _emitter.staticFunctionAccess(helperElement); |
2977 push(js.js( | 2976 push(js.js( |
2978 r'#(#, #, #)', [helper, receiver, typeName, js.js.number(index)])); | 2977 r'#(#, #, #)', [helper, receiver, typeName, js.js.number(index)])); |
2979 } else { | 2978 } else { |
2980 FunctionEntity helperElement = _helpers.getTypeArgumentByIndex; | 2979 FunctionEntity helperElement = _commonElements.getTypeArgumentByIndex; |
2981 _registry.registerStaticUse( | 2980 _registry.registerStaticUse( |
2982 new StaticUse.staticInvoke(helperElement, CallStructure.TWO_ARGS)); | 2981 new StaticUse.staticInvoke(helperElement, CallStructure.TWO_ARGS)); |
2983 js.Expression helper = _emitter.staticFunctionAccess(helperElement); | 2982 js.Expression helper = _emitter.staticFunctionAccess(helperElement); |
2984 push(js.js(r'#(#, #)', [helper, receiver, js.js.number(index)])); | 2983 push(js.js(r'#(#, #)', [helper, receiver, js.js.number(index)])); |
2985 } | 2984 } |
2986 } | 2985 } |
2987 | 2986 |
2988 void visitTypeInfoExpression(HTypeInfoExpression node) { | 2987 void visitTypeInfoExpression(HTypeInfoExpression node) { |
2989 List<js.Expression> arguments = <js.Expression>[]; | 2988 List<js.Expression> arguments = <js.Expression>[]; |
2990 for (HInstruction input in node.inputs) { | 2989 for (HInstruction input in node.inputs) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3031 return _closedWorld.anyStrictSubclassOf(cls, (ClassEntity subclass) { | 3030 return _closedWorld.anyStrictSubclassOf(cls, (ClassEntity subclass) { |
3032 return !_rtiSubstitutions.isTrivialSubstitution(subclass, cls); | 3031 return !_rtiSubstitutions.isTrivialSubstitution(subclass, cls); |
3033 }); | 3032 }); |
3034 } | 3033 } |
3035 | 3034 |
3036 @override | 3035 @override |
3037 void visitRef(HRef node) { | 3036 void visitRef(HRef node) { |
3038 visit(node.value); | 3037 visit(node.value); |
3039 } | 3038 } |
3040 } | 3039 } |
OLD | NEW |