OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of ssa; | 5 part of ssa; |
6 | 6 |
7 class SsaCodeGeneratorTask extends CompilerTask { | 7 class SsaCodeGeneratorTask extends CompilerTask { |
8 | 8 |
9 final JavaScriptBackend backend; | 9 final JavaScriptBackend backend; |
10 final SourceInformationStrategy sourceInformationFactory; | 10 final SourceInformationStrategy sourceInformationFactory; |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 controlFlowOperators = new Set<HInstruction>(), | 150 controlFlowOperators = new Set<HInstruction>(), |
151 breakAction = new Map<Entity, EntityAction>(), | 151 breakAction = new Map<Entity, EntityAction>(), |
152 continueAction = new Map<Entity, EntityAction>(); | 152 continueAction = new Map<Entity, EntityAction>(); |
153 | 153 |
154 Compiler get compiler => backend.compiler; | 154 Compiler get compiler => backend.compiler; |
155 | 155 |
156 NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter; | 156 NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter; |
157 | 157 |
158 CodegenRegistry get registry => work.registry; | 158 CodegenRegistry get registry => work.registry; |
159 | 159 |
| 160 BackendHelpers get helpers => backend.helpers; |
| 161 |
160 native.NativeEnqueuer get nativeEnqueuer { | 162 native.NativeEnqueuer get nativeEnqueuer { |
161 return compiler.enqueuer.codegen.nativeEnqueuer; | 163 return compiler.enqueuer.codegen.nativeEnqueuer; |
162 } | 164 } |
163 | 165 |
164 DiagnosticReporter get reporter => compiler.reporter; | 166 DiagnosticReporter get reporter => compiler.reporter; |
165 | 167 |
166 CoreClasses get coreClasses => compiler.coreClasses; | 168 CoreClasses get coreClasses => compiler.coreClasses; |
167 | 169 |
168 bool isGenerateAtUseSite(HInstruction instruction) { | 170 bool isGenerateAtUseSite(HInstruction instruction) { |
169 return generateAtUseSite.contains(instruction); | 171 return generateAtUseSite.contains(instruction); |
(...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
699 bool visitTryInfo(HTryBlockInformation info) { | 701 bool visitTryInfo(HTryBlockInformation info) { |
700 js.Block body = generateStatementsInNewBlock(info.body); | 702 js.Block body = generateStatementsInNewBlock(info.body); |
701 js.Catch catchPart = null; | 703 js.Catch catchPart = null; |
702 js.Block finallyPart = null; | 704 js.Block finallyPart = null; |
703 if (info.catchBlock != null) { | 705 if (info.catchBlock != null) { |
704 void register(ClassElement classElement) { | 706 void register(ClassElement classElement) { |
705 if (classElement != null) { | 707 if (classElement != null) { |
706 registry.registerInstantiatedClass(classElement); | 708 registry.registerInstantiatedClass(classElement); |
707 } | 709 } |
708 } | 710 } |
709 register(backend.jsPlainJavaScriptObjectClass); | 711 register(helpers.jsPlainJavaScriptObjectClass); |
710 register(backend.jsUnknownJavaScriptObjectClass); | 712 register(helpers.jsUnknownJavaScriptObjectClass); |
711 | 713 |
712 HLocalValue exception = info.catchVariable; | 714 HLocalValue exception = info.catchVariable; |
713 String name = variableNames.getName(exception); | 715 String name = variableNames.getName(exception); |
714 js.VariableDeclaration decl = new js.VariableDeclaration(name); | 716 js.VariableDeclaration decl = new js.VariableDeclaration(name); |
715 js.Block catchBlock = generateStatementsInNewBlock(info.catchBlock); | 717 js.Block catchBlock = generateStatementsInNewBlock(info.catchBlock); |
716 catchPart = new js.Catch(decl, catchBlock); | 718 catchPart = new js.Catch(decl, catchBlock); |
717 } | 719 } |
718 if (info.finallyBlock != null) { | 720 if (info.finallyBlock != null) { |
719 finallyPart = generateStatementsInNewBlock(info.finallyBlock); | 721 finallyPart = generateStatementsInNewBlock(info.finallyBlock); |
720 } | 722 } |
(...skipping 795 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1516 js.Expression receiverExpression = pop(); | 1518 js.Expression receiverExpression = pop(); |
1517 use(node.conditionalConstantInterceptor); | 1519 use(node.conditionalConstantInterceptor); |
1518 js.Expression constant = pop(); | 1520 js.Expression constant = pop(); |
1519 push(js.js('# && #', [receiverExpression, constant])); | 1521 push(js.js('# && #', [receiverExpression, constant])); |
1520 } else { | 1522 } else { |
1521 assert(node.inputs.length == 1); | 1523 assert(node.inputs.length == 1); |
1522 registry.registerSpecializedGetInterceptor(node.interceptedClasses); | 1524 registry.registerSpecializedGetInterceptor(node.interceptedClasses); |
1523 js.Name name = | 1525 js.Name name = |
1524 backend.namer.nameForGetInterceptor(node.interceptedClasses); | 1526 backend.namer.nameForGetInterceptor(node.interceptedClasses); |
1525 var isolate = new js.VariableUse( | 1527 var isolate = new js.VariableUse( |
1526 backend.namer.globalObjectFor(backend.interceptorsLibrary)); | 1528 backend.namer.globalObjectFor(helpers.interceptorsLibrary)); |
1527 use(node.receiver); | 1529 use(node.receiver); |
1528 List<js.Expression> arguments = <js.Expression>[pop()]; | 1530 List<js.Expression> arguments = <js.Expression>[pop()]; |
1529 push(js.propertyCall(isolate, name, arguments) | 1531 push(js.propertyCall(isolate, name, arguments) |
1530 .withSourceInformation(node.sourceInformation)); | 1532 .withSourceInformation(node.sourceInformation)); |
1531 registry.registerUseInterceptor(); | 1533 registry.registerUseInterceptor(); |
1532 } | 1534 } |
1533 } | 1535 } |
1534 | 1536 |
1535 visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 1537 visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
1536 use(node.receiver); | 1538 use(node.receiver); |
1537 js.Expression object = pop(); | 1539 js.Expression object = pop(); |
1538 String methodName; | 1540 String methodName; |
1539 List<js.Expression> arguments = visitArguments(node.inputs); | 1541 List<js.Expression> arguments = visitArguments(node.inputs); |
1540 Element target = node.element; | 1542 Element target = node.element; |
1541 | 1543 |
1542 // TODO(herhut): The namer should return the appropriate backendname here. | 1544 // TODO(herhut): The namer should return the appropriate backendname here. |
1543 if (target != null && !node.isInterceptedCall) { | 1545 if (target != null && !node.isInterceptedCall) { |
1544 if (target == backend.jsArrayAdd) { | 1546 if (target == helpers.jsArrayAdd) { |
1545 methodName = 'push'; | 1547 methodName = 'push'; |
1546 } else if (target == backend.jsArrayRemoveLast) { | 1548 } else if (target == helpers.jsArrayRemoveLast) { |
1547 methodName = 'pop'; | 1549 methodName = 'pop'; |
1548 } else if (target == backend.jsStringSplit) { | 1550 } else if (target == helpers.jsStringSplit) { |
1549 methodName = 'split'; | 1551 methodName = 'split'; |
1550 // Split returns a List, so we make sure the backend knows the | 1552 // Split returns a List, so we make sure the backend knows the |
1551 // list class is instantiated. | 1553 // list class is instantiated. |
1552 registry.registerInstantiatedClass(coreClasses.listClass); | 1554 registry.registerInstantiatedClass(coreClasses.listClass); |
1553 } else if (backend.isNative(target) && target.isFunction | 1555 } else if (backend.isNative(target) && target.isFunction |
1554 && !node.isInterceptedCall) { | 1556 && !node.isInterceptedCall) { |
1555 // A direct (i.e. non-interceptor) native call is the result of | 1557 // A direct (i.e. non-interceptor) native call is the result of |
1556 // optimization. The optimization ensures any type checks or | 1558 // optimization. The optimization ensures any type checks or |
1557 // conversions have been satisified. | 1559 // conversions have been satisified. |
1558 methodName = backend.getFixedBackendName(target); | 1560 methodName = backend.getFixedBackendName(target); |
(...skipping 17 matching lines...) Expand all Loading... |
1576 js.Name methodName = backend.namer.instanceMethodName(node.element); | 1578 js.Name methodName = backend.namer.instanceMethodName(node.element); |
1577 List<js.Expression> arguments = visitArguments(node.inputs); | 1579 List<js.Expression> arguments = visitArguments(node.inputs); |
1578 push(js.propertyCall(object, methodName, arguments) | 1580 push(js.propertyCall(object, methodName, arguments) |
1579 .withSourceInformation(node.sourceInformation)); | 1581 .withSourceInformation(node.sourceInformation)); |
1580 registry.registerStaticUse(node.element); | 1582 registry.registerStaticUse(node.element); |
1581 } | 1583 } |
1582 | 1584 |
1583 void visitOneShotInterceptor(HOneShotInterceptor node) { | 1585 void visitOneShotInterceptor(HOneShotInterceptor node) { |
1584 List<js.Expression> arguments = visitArguments(node.inputs); | 1586 List<js.Expression> arguments = visitArguments(node.inputs); |
1585 var isolate = new js.VariableUse( | 1587 var isolate = new js.VariableUse( |
1586 backend.namer.globalObjectFor(backend.interceptorsLibrary)); | 1588 backend.namer.globalObjectFor(helpers.interceptorsLibrary)); |
1587 Selector selector = node.selector; | 1589 Selector selector = node.selector; |
1588 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); | 1590 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); |
1589 js.Name methodName = backend.registerOneShotInterceptor(selector); | 1591 js.Name methodName = backend.registerOneShotInterceptor(selector); |
1590 push(js.propertyCall(isolate, methodName, arguments) | 1592 push(js.propertyCall(isolate, methodName, arguments) |
1591 .withSourceInformation(node.sourceInformation)); | 1593 .withSourceInformation(node.sourceInformation)); |
1592 if (selector.isGetter) { | 1594 if (selector.isGetter) { |
1593 registerGetter(node); | 1595 registerGetter(node); |
1594 } else if (selector.isSetter) { | 1596 } else if (selector.isSetter) { |
1595 registerSetter(node); | 1597 registerSetter(node); |
1596 } else { | 1598 } else { |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1790 | 1792 |
1791 visitFieldGet(HFieldGet node) { | 1793 visitFieldGet(HFieldGet node) { |
1792 use(node.receiver); | 1794 use(node.receiver); |
1793 Element element = node.element; | 1795 Element element = node.element; |
1794 if (node.isNullCheck) { | 1796 if (node.isNullCheck) { |
1795 // We access a JavaScript member we know all objects besides | 1797 // We access a JavaScript member we know all objects besides |
1796 // null and undefined have: V8 does not like accessing a member | 1798 // null and undefined have: V8 does not like accessing a member |
1797 // that does not exist. | 1799 // that does not exist. |
1798 push(new js.PropertyAccess.field(pop(), 'toString') | 1800 push(new js.PropertyAccess.field(pop(), 'toString') |
1799 .withSourceInformation(node.sourceInformation)); | 1801 .withSourceInformation(node.sourceInformation)); |
1800 } else if (element == backend.jsIndexableLength) { | 1802 } else if (element == helpers.jsIndexableLength) { |
1801 // We're accessing a native JavaScript property called 'length' | 1803 // We're accessing a native JavaScript property called 'length' |
1802 // on a JS String or a JS array. Therefore, the name of that | 1804 // on a JS String or a JS array. Therefore, the name of that |
1803 // property should not be mangled. | 1805 // property should not be mangled. |
1804 push(new js.PropertyAccess.field(pop(), 'length') | 1806 push(new js.PropertyAccess.field(pop(), 'length') |
1805 .withSourceInformation(node.sourceInformation)); | 1807 .withSourceInformation(node.sourceInformation)); |
1806 } else { | 1808 } else { |
1807 js.Name name = backend.namer.instanceFieldPropertyName(element); | 1809 js.Name name = backend.namer.instanceFieldPropertyName(element); |
1808 push(new js.PropertyAccess(pop(), name) | 1810 push(new js.PropertyAccess(pop(), name) |
1809 .withSourceInformation(node.sourceInformation)); | 1811 .withSourceInformation(node.sourceInformation)); |
1810 registry.registerFieldGetter(element); | 1812 registry.registerFieldGetter(element); |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2073 visitThis(HThis node) { | 2075 visitThis(HThis node) { |
2074 push(new js.This()); | 2076 push(new js.This()); |
2075 } | 2077 } |
2076 | 2078 |
2077 visitThrow(HThrow node) { | 2079 visitThrow(HThrow node) { |
2078 if (node.isRethrow) { | 2080 if (node.isRethrow) { |
2079 use(node.inputs[0]); | 2081 use(node.inputs[0]); |
2080 pushStatement(new js.Throw(pop()) | 2082 pushStatement(new js.Throw(pop()) |
2081 .withSourceInformation(node.sourceInformation)); | 2083 .withSourceInformation(node.sourceInformation)); |
2082 } else { | 2084 } else { |
2083 generateThrowWithHelper('wrapException', node.inputs[0], | 2085 generateThrowWithHelper(helpers.wrapExceptionHelper, node.inputs[0], |
2084 sourceInformation: node.sourceInformation); | 2086 sourceInformation: node.sourceInformation); |
2085 } | 2087 } |
2086 } | 2088 } |
2087 | 2089 |
2088 visitAwait(HAwait node) { | 2090 visitAwait(HAwait node) { |
2089 use(node.inputs[0]); | 2091 use(node.inputs[0]); |
2090 push(new js.Await(pop()) | 2092 push(new js.Await(pop()) |
2091 .withSourceInformation(node.sourceInformation)); | 2093 .withSourceInformation(node.sourceInformation)); |
2092 } | 2094 } |
2093 | 2095 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2134 } | 2136 } |
2135 assert(over != null || under != null); | 2137 assert(over != null || under != null); |
2136 js.Expression underOver = under == null | 2138 js.Expression underOver = under == null |
2137 ? over | 2139 ? over |
2138 : over == null | 2140 : over == null |
2139 ? under | 2141 ? under |
2140 : new js.Binary("||", under, over); | 2142 : new js.Binary("||", under, over); |
2141 js.Statement thenBody = new js.Block.empty(); | 2143 js.Statement thenBody = new js.Block.empty(); |
2142 js.Block oldContainer = currentContainer; | 2144 js.Block oldContainer = currentContainer; |
2143 currentContainer = thenBody; | 2145 currentContainer = thenBody; |
2144 generateThrowWithHelper('ioore', [node.array, node.reportedIndex]); | 2146 generateThrowWithHelper(helpers.throwIndexOutOfRangeException, |
| 2147 [node.array, node.reportedIndex]); |
2145 currentContainer = oldContainer; | 2148 currentContainer = oldContainer; |
2146 thenBody = unwrapStatement(thenBody); | 2149 thenBody = unwrapStatement(thenBody); |
2147 pushStatement(new js.If.noElse(underOver, thenBody) | 2150 pushStatement(new js.If.noElse(underOver, thenBody) |
2148 .withSourceInformation(node.sourceInformation)); | 2151 .withSourceInformation(node.sourceInformation)); |
2149 } else { | 2152 } else { |
2150 generateThrowWithHelper('ioore', [node.array, node.index]); | 2153 generateThrowWithHelper(helpers.throwIndexOutOfRangeException, |
| 2154 [node.array, node.index]); |
2151 } | 2155 } |
2152 } | 2156 } |
2153 | 2157 |
2154 void generateThrowWithHelper(String helperName, argument, | 2158 void generateThrowWithHelper(Element helper, argument, |
2155 {SourceInformation sourceInformation}) { | 2159 {SourceInformation sourceInformation}) { |
2156 Element helper = backend.findHelper(helperName); | |
2157 registry.registerStaticUse(helper); | 2160 registry.registerStaticUse(helper); |
2158 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); | 2161 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); |
2159 List arguments = []; | 2162 List arguments = []; |
2160 var location; | 2163 var location; |
2161 if (argument is List) { | 2164 if (argument is List) { |
2162 location = argument[0]; | 2165 location = argument[0]; |
2163 argument.forEach((instruction) { | 2166 argument.forEach((instruction) { |
2164 use(instruction); | 2167 use(instruction); |
2165 arguments.add(pop()); | 2168 arguments.add(pop()); |
2166 }); | 2169 }); |
2167 } else { | 2170 } else { |
2168 location = argument; | 2171 location = argument; |
2169 use(argument); | 2172 use(argument); |
2170 arguments.add(pop()); | 2173 arguments.add(pop()); |
2171 } | 2174 } |
2172 js.Call value = new js.Call(jsHelper, arguments.toList(growable: false), | 2175 js.Call value = new js.Call(jsHelper, arguments.toList(growable: false), |
2173 sourceInformation: sourceInformation); | 2176 sourceInformation: sourceInformation); |
2174 // BUG(4906): Using throw/return here adds to the size of the generated code | 2177 // BUG(4906): Using throw/return here adds to the size of the generated code |
2175 // but it has the advantage of explicitly telling the JS engine that | 2178 // but it has the advantage of explicitly telling the JS engine that |
2176 // this code path will terminate abruptly. Needs more work. | 2179 // this code path will terminate abruptly. Needs more work. |
2177 if (helperName == 'wrapException') { | 2180 if (helper == helpers.wrapExceptionHelper) { |
2178 pushStatement(new js.Throw(value) | 2181 pushStatement(new js.Throw(value) |
2179 .withSourceInformation(sourceInformation)); | 2182 .withSourceInformation(sourceInformation)); |
2180 } else { | 2183 } else { |
2181 Element element = work.element; | 2184 Element element = work.element; |
2182 if (element is FunctionElement && element.asyncMarker.isYielding) { | 2185 if (element is FunctionElement && element.asyncMarker.isYielding) { |
2183 // `return <expr>;` is illegal in a sync* or async* function. | 2186 // `return <expr>;` is illegal in a sync* or async* function. |
2184 // To have the the async-translator working, we avoid introducing | 2187 // To have the the async-translator working, we avoid introducing |
2185 // `return` nodes. | 2188 // `return` nodes. |
2186 pushStatement(new js.ExpressionStatement(value) | 2189 pushStatement(new js.ExpressionStatement(value) |
2187 .withSourceInformation(sourceInformation)); | 2190 .withSourceInformation(sourceInformation)); |
2188 } else { | 2191 } else { |
2189 pushStatement(new js.Return(value) | 2192 pushStatement(new js.Return(value) |
2190 .withSourceInformation(sourceInformation)); | 2193 .withSourceInformation(sourceInformation)); |
2191 } | 2194 } |
2192 } | 2195 } |
2193 } | 2196 } |
2194 | 2197 |
2195 visitThrowExpression(HThrowExpression node) { | 2198 visitThrowExpression(HThrowExpression node) { |
2196 HInstruction argument = node.inputs[0]; | 2199 HInstruction argument = node.inputs[0]; |
2197 use(argument); | 2200 use(argument); |
2198 | 2201 |
2199 Element helper = backend.findHelper("throwExpression"); | 2202 Element helper = helpers.throwExpressionHelper; |
2200 registry.registerStaticUse(helper); | 2203 registry.registerStaticUse(helper); |
2201 | 2204 |
2202 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); | 2205 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); |
2203 js.Call value = new js.Call(jsHelper, [pop()]) | 2206 js.Call value = new js.Call(jsHelper, [pop()]) |
2204 .withSourceInformation(node.sourceInformation); | 2207 .withSourceInformation(node.sourceInformation); |
2205 push(value); | 2208 push(value); |
2206 } | 2209 } |
2207 | 2210 |
2208 void visitSwitch(HSwitch node) { | 2211 void visitSwitch(HSwitch node) { |
2209 // Switches are handled using [visitSwitchInfo]. | 2212 // Switches are handled using [visitSwitchInfo]. |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2420 void checkNonNull(HInstruction input) { | 2423 void checkNonNull(HInstruction input) { |
2421 use(input); | 2424 use(input); |
2422 push(new js.Binary('!=', pop(), new js.LiteralNull())); | 2425 push(new js.Binary('!=', pop(), new js.LiteralNull())); |
2423 } | 2426 } |
2424 | 2427 |
2425 void checkType(HInstruction input, HInstruction interceptor, | 2428 void checkType(HInstruction input, HInstruction interceptor, |
2426 DartType type, | 2429 DartType type, |
2427 SourceInformation sourceInformation, | 2430 SourceInformation sourceInformation, |
2428 {bool negative: false}) { | 2431 {bool negative: false}) { |
2429 Element element = type.element; | 2432 Element element = type.element; |
2430 if (element == backend.jsArrayClass) { | 2433 if (element == helpers.jsArrayClass) { |
2431 checkArray(input, negative ? '!==': '==='); | 2434 checkArray(input, negative ? '!==': '==='); |
2432 return; | 2435 return; |
2433 } else if (element == backend.jsMutableArrayClass) { | 2436 } else if (element == helpers.jsMutableArrayClass) { |
2434 if (negative) { | 2437 if (negative) { |
2435 checkImmutableArray(input); | 2438 checkImmutableArray(input); |
2436 } else { | 2439 } else { |
2437 checkMutableArray(input); | 2440 checkMutableArray(input); |
2438 } | 2441 } |
2439 return; | 2442 return; |
2440 } else if (element == backend.jsExtendableArrayClass) { | 2443 } else if (element == helpers.jsExtendableArrayClass) { |
2441 if (negative) { | 2444 if (negative) { |
2442 checkFixedArray(input); | 2445 checkFixedArray(input); |
2443 } else { | 2446 } else { |
2444 checkExtendableArray(input); | 2447 checkExtendableArray(input); |
2445 } | 2448 } |
2446 return; | 2449 return; |
2447 } else if (element == backend.jsFixedArrayClass) { | 2450 } else if (element == helpers.jsFixedArrayClass) { |
2448 if (negative) { | 2451 if (negative) { |
2449 checkExtendableArray(input); | 2452 checkExtendableArray(input); |
2450 } else { | 2453 } else { |
2451 checkFixedArray(input); | 2454 checkFixedArray(input); |
2452 } | 2455 } |
2453 return; | 2456 return; |
2454 } else if (element == backend.jsUnmodifiableArrayClass) { | 2457 } else if (element == helpers.jsUnmodifiableArrayClass) { |
2455 if (negative) { | 2458 if (negative) { |
2456 checkMutableArray(input); | 2459 checkMutableArray(input); |
2457 } else { | 2460 } else { |
2458 checkImmutableArray(input); | 2461 checkImmutableArray(input); |
2459 } | 2462 } |
2460 return; | 2463 return; |
2461 } | 2464 } |
2462 if (interceptor != null) { | 2465 if (interceptor != null) { |
2463 checkTypeViaProperty(interceptor, type, sourceInformation, | 2466 checkTypeViaProperty(interceptor, type, sourceInformation, |
2464 negative: negative); | 2467 negative: negative); |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2683 TypeMask inputType = input.instructionType; | 2686 TypeMask inputType = input.instructionType; |
2684 // Figure out if it is beneficial to turn this into a null check. | 2687 // Figure out if it is beneficial to turn this into a null check. |
2685 // V8 generally prefers 'typeof' checks, but for integers and | 2688 // V8 generally prefers 'typeof' checks, but for integers and |
2686 // indexable primitives we cannot compile this test into a single | 2689 // indexable primitives we cannot compile this test into a single |
2687 // typeof check so the null check is cheaper. | 2690 // typeof check so the null check is cheaper. |
2688 bool isIntCheck = checkedType.containsOnlyInt(classWorld); | 2691 bool isIntCheck = checkedType.containsOnlyInt(classWorld); |
2689 bool turnIntoNumCheck = isIntCheck && input.isIntegerOrNull(compiler); | 2692 bool turnIntoNumCheck = isIntCheck && input.isIntegerOrNull(compiler); |
2690 bool turnIntoNullCheck = !turnIntoNumCheck | 2693 bool turnIntoNullCheck = !turnIntoNumCheck |
2691 && (checkedType.nullable() == inputType) | 2694 && (checkedType.nullable() == inputType) |
2692 && (isIntCheck | 2695 && (isIntCheck |
2693 || checkedType.satisfies(backend.jsIndexableClass, classWorld)); | 2696 || checkedType.satisfies(helpers.jsIndexableClass, classWorld)); |
2694 | 2697 |
2695 if (turnIntoNullCheck) { | 2698 if (turnIntoNullCheck) { |
2696 use(input); | 2699 use(input); |
2697 return new js.Binary("==", pop(), new js.LiteralNull()) | 2700 return new js.Binary("==", pop(), new js.LiteralNull()) |
2698 .withSourceInformation(input.sourceInformation); | 2701 .withSourceInformation(input.sourceInformation); |
2699 } else if (isIntCheck && !turnIntoNumCheck) { | 2702 } else if (isIntCheck && !turnIntoNumCheck) { |
2700 // input is !int | 2703 // input is !int |
2701 checkBigInt(input, '!==', input.sourceInformation); | 2704 checkBigInt(input, '!==', input.sourceInformation); |
2702 return pop(); | 2705 return pop(); |
2703 } else if (turnIntoNumCheck || checkedType.containsOnlyNum(classWorld)) { | 2706 } else if (turnIntoNumCheck || checkedType.containsOnlyNum(classWorld)) { |
(...skipping 20 matching lines...) Expand all Loading... |
2724 // sufficient for doing an argument or receiver check. | 2727 // sufficient for doing an argument or receiver check. |
2725 assert(compiler.trustTypeAnnotations || | 2728 assert(compiler.trustTypeAnnotations || |
2726 !node.checkedType.containsOnlyInt(classWorld) || | 2729 !node.checkedType.containsOnlyInt(classWorld) || |
2727 node.checkedInput.isIntegerOrNull(compiler)); | 2730 node.checkedInput.isIntegerOrNull(compiler)); |
2728 js.Expression test = generateReceiverOrArgumentTypeTest( | 2731 js.Expression test = generateReceiverOrArgumentTypeTest( |
2729 node.checkedInput, node.checkedType); | 2732 node.checkedInput, node.checkedType); |
2730 js.Block oldContainer = currentContainer; | 2733 js.Block oldContainer = currentContainer; |
2731 js.Statement body = new js.Block.empty(); | 2734 js.Statement body = new js.Block.empty(); |
2732 currentContainer = body; | 2735 currentContainer = body; |
2733 if (node.isArgumentTypeCheck) { | 2736 if (node.isArgumentTypeCheck) { |
2734 generateThrowWithHelper('iae', | 2737 generateThrowWithHelper( |
| 2738 helpers.throwIllegalArgumentException, |
2735 node.checkedInput, | 2739 node.checkedInput, |
2736 sourceInformation: node.sourceInformation); | 2740 sourceInformation: node.sourceInformation); |
2737 } else if (node.isReceiverTypeCheck) { | 2741 } else if (node.isReceiverTypeCheck) { |
2738 use(node.checkedInput); | 2742 use(node.checkedInput); |
2739 js.Name methodName = | 2743 js.Name methodName = |
2740 backend.namer.invocationName(node.receiverTypeCheckSelector); | 2744 backend.namer.invocationName(node.receiverTypeCheckSelector); |
2741 js.Expression call = js.propertyCall(pop(), methodName, []); | 2745 js.Expression call = js.propertyCall(pop(), methodName, []); |
2742 pushStatement(new js.Return(call)); | 2746 pushStatement(new js.Return(call)); |
2743 } | 2747 } |
2744 currentContainer = oldContainer; | 2748 currentContainer = oldContainer; |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2819 var arguments = [ | 2823 var arguments = [ |
2820 returnType, | 2824 returnType, |
2821 new js.ArrayInitializer(parameterTypes), | 2825 new js.ArrayInitializer(parameterTypes), |
2822 new js.ObjectInitializer(namedParameters)]; | 2826 new js.ObjectInitializer(namedParameters)]; |
2823 push(js.js('#(#)', [accessHelper('buildNamedFunctionType'), arguments])); | 2827 push(js.js('#(#)', [accessHelper('buildNamedFunctionType'), arguments])); |
2824 } | 2828 } |
2825 } | 2829 } |
2826 | 2830 |
2827 void visitReadTypeVariable(HReadTypeVariable node) { | 2831 void visitReadTypeVariable(HReadTypeVariable node) { |
2828 TypeVariableElement element = node.dartType.element; | 2832 TypeVariableElement element = node.dartType.element; |
2829 Element helperElement = backend.findHelper('convertRtiToRuntimeType'); | 2833 Element helperElement = helpers.convertRtiToRuntimeType; |
2830 registry.registerStaticUse(helperElement); | 2834 registry.registerStaticUse(helperElement); |
2831 | 2835 |
2832 use(node.inputs[0]); | 2836 use(node.inputs[0]); |
2833 if (node.hasReceiver) { | 2837 if (node.hasReceiver) { |
2834 if (backend.isInterceptorClass(element.enclosingClass)) { | 2838 if (backend.isInterceptorClass(element.enclosingClass)) { |
2835 int index = element.index; | 2839 int index = element.index; |
2836 js.Expression receiver = pop(); | 2840 js.Expression receiver = pop(); |
2837 js.Expression helper = backend.emitter | 2841 js.Expression helper = backend.emitter |
2838 .staticFunctionAccess(helperElement); | 2842 .staticFunctionAccess(helperElement); |
2839 push(js.js(r'#(#.$builtinTypeInfo && #.$builtinTypeInfo[#])', | 2843 push(js.js(r'#(#.$builtinTypeInfo && #.$builtinTypeInfo[#])', |
2840 [helper, receiver, receiver, js.js.number(index)])); | 2844 [helper, receiver, receiver, js.js.number(index)])); |
2841 } else { | 2845 } else { |
2842 backend.emitter.registerReadTypeVariable(element); | 2846 backend.emitter.registerReadTypeVariable(element); |
2843 push(js.js('#.#()', | 2847 push(js.js('#.#()', |
2844 [pop(), backend.namer.nameForReadTypeVariable(element)])); | 2848 [pop(), backend.namer.nameForReadTypeVariable(element)])); |
2845 } | 2849 } |
2846 } else { | 2850 } else { |
2847 push(js.js('#(#)', [ | 2851 push(js.js('#(#)', [ |
2848 backend.emitter.staticFunctionAccess( | 2852 backend.emitter.staticFunctionAccess(helperElement), |
2849 backend.findHelper('convertRtiToRuntimeType')), | |
2850 pop()])); | 2853 pop()])); |
2851 } | 2854 } |
2852 } | 2855 } |
2853 | 2856 |
2854 void visitInterfaceType(HInterfaceType node) { | 2857 void visitInterfaceType(HInterfaceType node) { |
2855 List<js.Expression> typeArguments = <js.Expression>[]; | 2858 List<js.Expression> typeArguments = <js.Expression>[]; |
2856 for (HInstruction type in node.inputs) { | 2859 for (HInstruction type in node.inputs) { |
2857 use(type); | 2860 use(type); |
2858 typeArguments.add(pop()); | 2861 typeArguments.add(pop()); |
2859 } | 2862 } |
2860 | 2863 |
2861 ClassElement cls = node.dartType.element; | 2864 ClassElement cls = node.dartType.element; |
2862 var arguments = [backend.emitter.typeAccess(cls)]; | 2865 var arguments = [backend.emitter.typeAccess(cls)]; |
2863 if (!typeArguments.isEmpty) { | 2866 if (!typeArguments.isEmpty) { |
2864 arguments.add(new js.ArrayInitializer(typeArguments)); | 2867 arguments.add(new js.ArrayInitializer(typeArguments)); |
2865 } | 2868 } |
2866 push(js.js('#(#)', [accessHelper('buildInterfaceType'), arguments])); | 2869 push(js.js('#(#)', [accessHelper('buildInterfaceType'), arguments])); |
2867 } | 2870 } |
2868 | 2871 |
2869 void visitVoidType(HVoidType node) { | 2872 void visitVoidType(HVoidType node) { |
2870 push(js.js('#()', accessHelper('getVoidRuntimeType'))); | 2873 push(js.js('#()', accessHelper('getVoidRuntimeType'))); |
2871 } | 2874 } |
2872 | 2875 |
2873 void visitDynamicType(HDynamicType node) { | 2876 void visitDynamicType(HDynamicType node) { |
2874 push(js.js('#()', accessHelper('getDynamicRuntimeType'))); | 2877 push(js.js('#()', accessHelper('getDynamicRuntimeType'))); |
2875 } | 2878 } |
2876 | 2879 |
2877 js.PropertyAccess accessHelper(String name) { | 2880 js.PropertyAccess accessHelper(String name) { |
2878 Element helper = backend.findHelper(name); | 2881 Element helper = helpers.findHelper(name); |
2879 if (helper == null) { | 2882 if (helper == null) { |
2880 // For mocked-up tests. | 2883 // For mocked-up tests. |
2881 return js.js('(void 0).$name'); | 2884 return js.js('(void 0).$name'); |
2882 } | 2885 } |
2883 registry.registerStaticUse(helper); | 2886 registry.registerStaticUse(helper); |
2884 return backend.emitter.staticFunctionAccess(helper); | 2887 return backend.emitter.staticFunctionAccess(helper); |
2885 } | 2888 } |
2886 | 2889 |
2887 @override | 2890 @override |
2888 void visitRef(HRef node) { | 2891 void visitRef(HRef node) { |
2889 visit(node.value); | 2892 visit(node.value); |
2890 } | 2893 } |
2891 } | 2894 } |
OLD | NEW |