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