Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(81)

Side by Side Diff: lib/src/codegen/js_codegen.dart

Issue 1487213002: Special-case top-level final JS fields. (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: rebased Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/runtime/dart/js.js ('k') | tool/input_sdk/private/utils.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 library dev_compiler.src.codegen.js_codegen; 5 library dev_compiler.src.codegen.js_codegen;
6 6
7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; 7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet;
8 8
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator;
(...skipping 1303 matching lines...) Expand 10 before | Expand all | Expand 10 after
1314 if (needsTagging) { 1314 if (needsTagging) {
1315 body.add(_emitFunctionTagged(id, node.element.type, topLevel: true) 1315 body.add(_emitFunctionTagged(id, node.element.type, topLevel: true)
1316 .toStatement()); 1316 .toStatement());
1317 } 1317 }
1318 1318
1319 if (isPublic(name)) _addExport(name); 1319 if (isPublic(name)) _addExport(name);
1320 return _statement(body); 1320 return _statement(body);
1321 } 1321 }
1322 1322
1323 bool _isInlineJSFunction(FunctionExpression functionExpression) { 1323 bool _isInlineJSFunction(FunctionExpression functionExpression) {
1324 bool isJsInvocation(Expression expr) =>
1325 expr is MethodInvocation && isInlineJS(expr.methodName.staticElement);
1326
1327 var body = functionExpression.body; 1324 var body = functionExpression.body;
1328 if (body is ExpressionFunctionBody) { 1325 if (body is ExpressionFunctionBody) {
1329 return isJsInvocation(body.expression); 1326 return _isJSInvocation(body.expression);
1330 } else if (body is BlockFunctionBody) { 1327 } else if (body is BlockFunctionBody) {
1331 if (body.block.statements.length == 1) { 1328 if (body.block.statements.length == 1) {
1332 var stat = body.block.statements.single; 1329 var stat = body.block.statements.single;
1333 if (stat is ReturnStatement) { 1330 if (stat is ReturnStatement) {
1334 return isJsInvocation(stat.expression); 1331 return _isJSInvocation(stat.expression);
1335 } 1332 }
1336 } 1333 }
1337 } 1334 }
1338 return false; 1335 return false;
1339 } 1336 }
1340 1337
1338 bool _isJSInvocation(Expression expr) =>
1339 expr is MethodInvocation && isInlineJS(expr.methodName.staticElement);
1340
1341 // Simplify `(args) => ((x, y) => { ... })(x, y)` to `(args) => { ... }`. 1341 // Simplify `(args) => ((x, y) => { ... })(x, y)` to `(args) => { ... }`.
1342 // Note: we don't check if the top-level args match the ones passed through 1342 // Note: we don't check if the top-level args match the ones passed through
1343 // the arrow function, which allows silently passing args through to the 1343 // the arrow function, which allows silently passing args through to the
1344 // body (which only works if we don't do weird renamings of Dart params). 1344 // body (which only works if we don't do weird renamings of Dart params).
1345 JS.Fun _simplifyPassThroughArrowFunCallBody(JS.Fun fn) { 1345 JS.Fun _simplifyPassThroughArrowFunCallBody(JS.Fun fn) {
1346 String getIdent(JS.Node node) => node is JS.Identifier ? node.name : null; 1346 String getIdent(JS.Node node) => node is JS.Identifier ? node.name : null;
1347 List<String> getIdents(List params) => 1347 List<String> getIdents(List params) =>
1348 params.map(getIdent).toList(growable: false); 1348 params.map(getIdent).toList(growable: false);
1349 1349
1350 if (fn.body is JS.Block && fn.body.statements.length == 1) { 1350 if (fn.body is JS.Block && fn.body.statements.length == 1) {
(...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after
1737 return _maybeQualifiedName(element); 1737 return _maybeQualifiedName(element);
1738 } 1738 }
1739 1739
1740 JS.Expression _maybeQualifiedName(Element e, [String name]) { 1740 JS.Expression _maybeQualifiedName(Element e, [String name]) {
1741 var libName = _libraryName(e.library); 1741 var libName = _libraryName(e.library);
1742 var nameExpr = _propertyName(name ?? e.name); 1742 var nameExpr = _propertyName(name ?? e.name);
1743 1743
1744 // Always qualify: 1744 // Always qualify:
1745 // * mutable top-level fields 1745 // * mutable top-level fields
1746 // * elements from other libraries 1746 // * elements from other libraries
1747 bool mutableTopLevel = e is TopLevelVariableElement && !e.isConst; 1747 bool mutableTopLevel = e is TopLevelVariableElement &&
1748 !e.isConst &&
1749 !_isFinalJSDecl(e.computeNode());
1748 bool fromAnotherLibrary = e.library != currentLibrary; 1750 bool fromAnotherLibrary = e.library != currentLibrary;
1749 if (mutableTopLevel || fromAnotherLibrary) { 1751 if (mutableTopLevel || fromAnotherLibrary) {
1750 return new JS.PropertyAccess(libName, nameExpr); 1752 return new JS.PropertyAccess(libName, nameExpr);
1751 } 1753 }
1752 1754
1753 var id = new JS.MaybeQualifiedId(libName, nameExpr); 1755 var id = new JS.MaybeQualifiedId(libName, nameExpr);
1754 _qualifiedIds.add(new Tuple2(e, id)); 1756 _qualifiedIds.add(new Tuple2(e, id));
1755 return id; 1757 return id;
1756 } 1758 }
1757 1759
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after
2083 } 2085 }
2084 2086
2085 @override 2087 @override
2086 visitVariableDeclaration(VariableDeclaration node) { 2088 visitVariableDeclaration(VariableDeclaration node) {
2087 if (node.element is PropertyInducingElement) return _emitStaticField(node); 2089 if (node.element is PropertyInducingElement) return _emitStaticField(node);
2088 2090
2089 var name = new JS.Identifier(node.name.name); 2091 var name = new JS.Identifier(node.name.name);
2090 return new JS.VariableInitialization(name, _visitInitializer(node)); 2092 return new JS.VariableInitialization(name, _visitInitializer(node));
2091 } 2093 }
2092 2094
2095 bool _isFinalJSDecl(AstNode field) => field is VariableDeclaration &&
2096 field.isFinal &&
2097 _isJSInvocation(field.initializer);
2098
2093 /// Emits a static or top-level field. 2099 /// Emits a static or top-level field.
2094 JS.Statement _emitStaticField(VariableDeclaration field) { 2100 JS.Statement _emitStaticField(VariableDeclaration field) {
2095 PropertyInducingElement element = field.element; 2101 PropertyInducingElement element = field.element;
2096 assert(element.isStatic); 2102 assert(element.isStatic);
2097 2103
2098 bool eagerInit; 2104 bool eagerInit;
2099 JS.Expression jsInit; 2105 JS.Expression jsInit;
2100 if (field.isConst || _constField.isFieldInitConstant(field)) { 2106 if (field.isConst || _constField.isFieldInitConstant(field)) {
2101 // If the field is constant, try and generate it at the top level. 2107 // If the field is constant, try and generate it at the top level.
2102 _loader.startTopLevel(element); 2108 _loader.startTopLevel(element);
2103 jsInit = _visitInitializer(field); 2109 jsInit = _visitInitializer(field);
2104 _loader.finishTopLevel(element); 2110 _loader.finishTopLevel(element);
2105 eagerInit = _loader.isLoaded(element); 2111 eagerInit = _loader.isLoaded(element);
2106 } else { 2112 } else {
2107 jsInit = _visitInitializer(field); 2113 jsInit = _visitInitializer(field);
2108 eagerInit = false; 2114 eagerInit = false;
2109 } 2115 }
2110 2116
2117 // Treat `final x = JS('', '...')` as a const (non-lazy) to help compile
2118 // runtime helpers.
2119 var isJSTopLevel = field.isFinal && _isFinalJSDecl(field);
2120 if (isJSTopLevel) eagerInit = true;
2121
2111 var fieldName = field.name.name; 2122 var fieldName = field.name.name;
2112 if (field.isConst && eagerInit && element is TopLevelVariableElement) { 2123 if ((field.isConst && eagerInit && element is TopLevelVariableElement) ||
2124 isJSTopLevel) {
2113 // constant fields don't change, so we can generate them as `let` 2125 // constant fields don't change, so we can generate them as `let`
2114 // but add them to the module's exports. However, make sure we generate 2126 // but add them to the module's exports. However, make sure we generate
2115 // anything they depend on first. 2127 // anything they depend on first.
2116 2128
2117 if (isPublic(fieldName)) _addExport(fieldName); 2129 if (isPublic(fieldName)) _addExport(fieldName);
2118 var declKeyword = field.isConst || field.isFinal ? 'const' : 'let'; 2130 var declKeyword = field.isConst || field.isFinal ? 'const' : 'let';
2119 return annotateVariable( 2131 return annotateVariable(
2120 js.statement( 2132 js.statement(
2121 '$declKeyword # = #;', [new JS.Identifier(fieldName), jsInit]), 2133 '$declKeyword # = #;', [new JS.Identifier(fieldName), jsInit]),
2122 field.element); 2134 field.element);
(...skipping 1294 matching lines...) Expand 10 before | Expand all | Expand 10 after
3417 3429
3418 /// A special kind of element created by the compiler, signifying a temporary 3430 /// A special kind of element created by the compiler, signifying a temporary
3419 /// variable. These objects use instance equality, and should be shared 3431 /// variable. These objects use instance equality, and should be shared
3420 /// everywhere in the tree where they are treated as the same variable. 3432 /// everywhere in the tree where they are treated as the same variable.
3421 class TemporaryVariableElement extends LocalVariableElementImpl { 3433 class TemporaryVariableElement extends LocalVariableElementImpl {
3422 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); 3434 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name);
3423 3435
3424 int get hashCode => identityHashCode(this); 3436 int get hashCode => identityHashCode(this);
3425 bool operator ==(Object other) => identical(this, other); 3437 bool operator ==(Object other) => identical(this, other);
3426 } 3438 }
OLDNEW
« no previous file with comments | « lib/runtime/dart/js.js ('k') | tool/input_sdk/private/utils.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698