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

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

Issue 1122133003: fixes #157, renaming local library identifiers if needed. (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: fix core.Symbol reference Created 5 years, 7 months 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
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; 7 import 'dart:collection' show HashSet, HashMap;
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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 final HashSet<FieldElement> _fieldsNeedingStorage; 61 final HashSet<FieldElement> _fieldsNeedingStorage;
62 62
63 /// The variable for the target of the current `..` cascade expression. 63 /// The variable for the target of the current `..` cascade expression.
64 SimpleIdentifier _cascadeTarget; 64 SimpleIdentifier _cascadeTarget;
65 65
66 /// The variable for the current catch clause 66 /// The variable for the current catch clause
67 SimpleIdentifier _catchParameter; 67 SimpleIdentifier _catchParameter;
68 68
69 ConstantEvaluator _constEvaluator; 69 ConstantEvaluator _constEvaluator;
70 70
71 /// Imported libraries, and the temporaries used to refer to them.
72 final _imports = new Map<LibraryElement, JS.TemporaryId>();
71 final _exports = new Set<String>(); 73 final _exports = new Set<String>();
72 final _lazyFields = <VariableDeclaration>[]; 74 final _lazyFields = <VariableDeclaration>[];
73 final _properties = <FunctionDeclaration>[]; 75 final _properties = <FunctionDeclaration>[];
74 final _privateNames = new HashMap<String, JS.TemporaryId>(); 76 final _privateNames = new HashMap<String, JS.TemporaryId>();
75 final _extensionMethodNames = new HashSet<String>(); 77 final _extensionMethodNames = new HashSet<String>();
76 final _pendingStatements = <JS.Statement>[]; 78 final _pendingStatements = <JS.Statement>[];
77 final _temps = new HashMap<Element, JS.TemporaryId>(); 79 final _temps = new HashMap<Element, JS.TemporaryId>();
78 80
79 /// The name for the library's exports inside itself. 81 /// The name for the library's exports inside itself.
80 /// This much be a constant because we interpolate it into template strings,
81 /// and otherwise it would break caching for them.
82 /// `exports` was chosen as the most similar to ES module patterns. 82 /// `exports` was chosen as the most similar to ES module patterns.
83 final _exportsVar = new JS.TemporaryId('exports'); 83 final _exportsVar = new JS.TemporaryId('exports');
84 final _namedArgTemp = new JS.TemporaryId('opts'); 84 final _namedArgTemp = new JS.TemporaryId('opts');
85 85
86 /// Classes we have not emitted yet. Values can be [ClassDeclaration] or 86 /// Classes we have not emitted yet. Values can be [ClassDeclaration] or
87 /// [ClassTypeAlias]. 87 /// [ClassTypeAlias].
88 final _pendingClasses = new HashMap<Element, CompilationUnitMember>(); 88 final _pendingClasses = new HashMap<Element, CompilationUnitMember>();
89 89
90 /// Memoized results of [_lazyClass]. 90 /// Memoized results of [_lazyClass].
91 final _lazyClassMemo = new HashMap<Element, bool>(); 91 final _lazyClassMemo = new HashMap<Element, bool>();
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 134
135 assert(_pendingClasses.isEmpty); 135 assert(_pendingClasses.isEmpty);
136 136
137 if (_exports.isNotEmpty) body.add(js.comment('Exports:')); 137 if (_exports.isNotEmpty) body.add(js.comment('Exports:'));
138 138
139 // TODO(jmesserly): make these immutable in JS? 139 // TODO(jmesserly): make these immutable in JS?
140 for (var name in _exports) { 140 for (var name in _exports) {
141 body.add(js.statement('#.# = #;', [_exportsVar, name, name])); 141 body.add(js.statement('#.# = #;', [_exportsVar, name, name]));
142 } 142 }
143 143
144 var name = jsLibraryName(libraryInfo.library); 144 var name = jsLibraryName(currentLibrary);
145 var defaultValue = js.call(jsDefaultValue);
146 var imports = _imports.values.map((i) => i.name);
147 var libraries = [name]..addAll(imports);
145 148
146 var defaultValue = js.call(jsDefaultValue); 149 var globals = new JS.VariableDeclarationList('var', libraries
150 .map((l) => new JS.VariableInitialization(new JS.Identifier(l), null))
151 .toList(growable: false));
152
153 // TODO(jmesserly): it would be great to run the renamer on the body,
154 // then figure out if we really need each of these parameters.
155 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34
156 var importInit = [js.call('# || (# = #)', [name, name, defaultValue])];
157 _imports.forEach((library, temp) {
158 var name = new JS.Identifier(temp.name);
159 if (_libraryMightNotBeLoaded(library)) {
160 importInit.add(js.call('# || (# = {})', [name, name]));
161 } else {
162 importInit.add(name);
163 }
164 });
165
147 return new JS.Program([ 166 return new JS.Program([
148 js.statement('var #;', name), 167 globals.toStatement(),
149 js.statement("(function(#) { 'use strict'; #; })(# || (# = #));", [ 168 js.statement("(function(#) { 'use strict'; #; })(#);", [
150 _exportsVar, 169 [_exportsVar]..addAll(_imports.values),
151 body, 170 body,
152 name, 171 importInit
153 name,
154 defaultValue
155 ]) 172 ])
156 ]); 173 ]);
157 } 174 }
158 175
159 JS.Identifier _initSymbol(JS.Identifier id) { 176 JS.Identifier _initSymbol(JS.Identifier id) {
160 var s = js.statement('let # = $_SYMBOL(#);', [id, js.string(id.name, "'")]); 177 var s = js.statement('let # = $_SYMBOL(#);', [id, js.string(id.name, "'")]);
161 _pendingStatements.add(s); 178 _pendingStatements.add(s);
162 return id; 179 return id;
163 } 180 }
164 181
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 /// on this library via some transitive import path. 487 /// on this library via some transitive import path.
471 /// 488 ///
472 /// If we could control the global import ordering, we could eliminate some 489 /// If we could control the global import ordering, we could eliminate some
473 /// of these cases, by ordering the imports of the cyclic libraries in an 490 /// of these cases, by ordering the imports of the cyclic libraries in an
474 /// optimal way. For example, we could order the libraries in a cycle to 491 /// optimal way. For example, we could order the libraries in a cycle to
475 /// minimize laziness. However, we currently assume we cannot control the 492 /// minimize laziness. However, we currently assume we cannot control the
476 /// order that the cycle of libraries will be loaded in. 493 /// order that the cycle of libraries will be loaded in.
477 bool _typeMightNotBeLoaded(DartType type) { 494 bool _typeMightNotBeLoaded(DartType type) {
478 var library = type.element.library; 495 var library = type.element.library;
479 if (library == currentLibrary) return _lazyClass(type); 496 if (library == currentLibrary) return _lazyClass(type);
497 return _libraryMightNotBeLoaded(library);
498 }
480 499
500 bool _libraryMightNotBeLoaded(LibraryElement library) {
481 // The SDK is a special case: we optimize the order to prevent laziness. 501 // The SDK is a special case: we optimize the order to prevent laziness.
482 if (library.isInSdk) { 502 if (library.isInSdk) {
483 // SDK is loaded before non-SDK libraies 503 // SDK is loaded before non-SDK libraies
484 if (!currentLibrary.isInSdk) return false; 504 if (!currentLibrary.isInSdk) return false;
485 505
486 // Compute the order of both SDK libraries. If unknown, assume it's after. 506 // Compute the order of both SDK libraries. If unknown, assume it's after.
487 var classOrder = corelibOrder.indexOf(library.name); 507 var classOrder = corelibOrder.indexOf(library.name);
488 if (classOrder == -1) classOrder = corelibOrder.length; 508 if (classOrder == -1) classOrder = corelibOrder.length;
489 509
490 var currentOrder = corelibOrder.indexOf(currentLibrary.name); 510 var currentOrder = corelibOrder.indexOf(currentLibrary.name);
(...skipping 603 matching lines...) Expand 10 before | Expand all | Expand 10 after
1094 } 1114 }
1095 1115
1096 // Get the original declaring element. If we had a property accessor, this 1116 // Get the original declaring element. If we had a property accessor, this
1097 // indirects back to a (possibly synthetic) field. 1117 // indirects back to a (possibly synthetic) field.
1098 var element = accessor; 1118 var element = accessor;
1099 if (element is PropertyAccessorElement) element = accessor.variable; 1119 if (element is PropertyAccessorElement) element = accessor.variable;
1100 var name = element.name; 1120 var name = element.name;
1101 1121
1102 // library member 1122 // library member
1103 if (element.enclosingElement is CompilationUnitElement && 1123 if (element.enclosingElement is CompilationUnitElement &&
1104 (element.library != libraryInfo.library || 1124 (element.library != currentLibrary ||
1105 element is TopLevelVariableElement && !element.isConst)) { 1125 element is TopLevelVariableElement && !element.isConst)) {
1106 var memberName = _emitMemberName(name, isStatic: true); 1126 var memberName = _emitMemberName(name, isStatic: true);
1107 return js.call('#.#', [_libraryName(element.library), memberName]); 1127 return js.call('#.#', [_libraryName(element.library), memberName]);
1108 } 1128 }
1109 1129
1110 // Unqualified class member. This could mean implicit-this, or implicit 1130 // Unqualified class member. This could mean implicit-this, or implicit
1111 // call to a static from the same class. 1131 // call to a static from the same class.
1112 if (element is ClassMemberElement && element is! ConstructorElement) { 1132 if (element is ClassMemberElement && element is! ConstructorElement) {
1113 bool isStatic = element.isStatic; 1133 bool isStatic = element.isStatic;
1114 var type = element.enclosingElement.type; 1134 var type = element.enclosingElement.type;
(...skipping 1121 matching lines...) Expand 10 before | Expand all | Expand 10 after
2236 2256
2237 @override 2257 @override
2238 visitNullLiteral(NullLiteral node) => new JS.LiteralNull(); 2258 visitNullLiteral(NullLiteral node) => new JS.LiteralNull();
2239 2259
2240 @override 2260 @override
2241 visitSymbolLiteral(SymbolLiteral node) { 2261 visitSymbolLiteral(SymbolLiteral node) {
2242 // TODO(vsm): When we canonicalize, we need to treat private symbols 2262 // TODO(vsm): When we canonicalize, we need to treat private symbols
2243 // correctly. 2263 // correctly.
2244 var name = js.string(node.components.join('.'), "'"); 2264 var name = js.string(node.components.join('.'), "'");
2245 var nameHint = 'symbol_' + node.components.join('_'); 2265 var nameHint = 'symbol_' + node.components.join('_');
2246 return _const(node, js.call('new core.Symbol(#)', name), nameHint); 2266 return _const(
2267 node, new JS.New(_emitTypeName(types.symbolType), [name]), nameHint);
2247 } 2268 }
2248 2269
2249 @override 2270 @override
2250 visitListLiteral(ListLiteral node) { 2271 visitListLiteral(ListLiteral node) {
2251 JS.Expression list = new JS.ArrayInitializer(_visitList(node.elements)); 2272 JS.Expression list = new JS.ArrayInitializer(_visitList(node.elements));
2252 2273
2253 ParameterizedType type = node.staticType; 2274 ParameterizedType type = node.staticType;
2254 if (type.typeArguments.any((a) => a != types.dynamicType)) { 2275 if (type.typeArguments.any((a) => a != types.dynamicType)) {
2255 list = js.call('dart.setType(#, #)', [list, _emitTypeName(type)]); 2276 list = js.call('dart.setType(#, #)', [list, _emitTypeName(type)]);
2256 } 2277 }
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
2485 bool _externalOrNative(node) => 2506 bool _externalOrNative(node) =>
2486 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; 2507 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody;
2487 2508
2488 FunctionBody _functionBody(node) => 2509 FunctionBody _functionBody(node) =>
2489 node is FunctionDeclaration ? node.functionExpression.body : node.body; 2510 node is FunctionDeclaration ? node.functionExpression.body : node.body;
2490 2511
2491 /// Choose a canonical name from the library element. 2512 /// Choose a canonical name from the library element.
2492 /// This never uses the library's name (the identifier in the `library` 2513 /// This never uses the library's name (the identifier in the `library`
2493 /// declaration) as it doesn't have any meaningful rules enforced. 2514 /// declaration) as it doesn't have any meaningful rules enforced.
2494 JS.Identifier _libraryName(LibraryElement library) { 2515 JS.Identifier _libraryName(LibraryElement library) {
2495 if (library == libraryInfo.library) return _exportsVar; 2516 if (library == currentLibrary) return _exportsVar;
2496 return new JS.Identifier(jsLibraryName(library)); 2517 return _imports.putIfAbsent(
2518 library, () => new JS.TemporaryId(jsLibraryName(library)));
2497 } 2519 }
2498 2520
2499 DartType getStaticType(Expression e) => rules.getStaticType(e); 2521 DartType getStaticType(Expression e) => rules.getStaticType(e);
2500 } 2522 }
2501 2523
2502 class JSGenerator extends CodeGenerator { 2524 class JSGenerator extends CodeGenerator {
2503 final CompilerOptions options; 2525 final CompilerOptions options;
2504 2526
2505 /// For fast lookup of extension methods, we first check the name, then do a 2527 /// For fast lookup of extension methods, we first check the name, then do a
2506 /// (possibly expensive) subtype test to see if it matches one of the types 2528 /// (possibly expensive) subtype test to see if it matches one of the types
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
2570 // TODO(jmesserly): validate the library. See issue #135. 2592 // TODO(jmesserly): validate the library. See issue #135.
2571 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName'; 2593 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName';
2572 2594
2573 bool _isJsPeerInterface(DartObjectImpl value) => 2595 bool _isJsPeerInterface(DartObjectImpl value) =>
2574 value.type.name == 'JsPeerInterface'; 2596 value.type.name == 'JsPeerInterface';
2575 2597
2576 // TODO(jacobr): we would like to do something like the following 2598 // TODO(jacobr): we would like to do something like the following
2577 // but we don't have summary support yet. 2599 // but we don't have summary support yet.
2578 // bool _supportJsExtensionMethod(AnnotatedNode node) => 2600 // bool _supportJsExtensionMethod(AnnotatedNode node) =>
2579 // _getAnnotation(node, "SupportJsExtensionMethod") != null; 2601 // _getAnnotation(node, "SupportJsExtensionMethod") != null;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698