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

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

Issue 1530563003: Generate all runtime files from dart. (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Reverted to new .dart files in input_sdk: please compare them against previous patchset 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/html_common.js ('k') | lib/src/codegen/js_interop.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 20 matching lines...) Expand all
31 31
32 import 'code_generator.dart'; 32 import 'code_generator.dart';
33 import 'js_field_storage.dart'; 33 import 'js_field_storage.dart';
34 import 'js_interop.dart'; 34 import 'js_interop.dart';
35 import 'js_names.dart' as JS; 35 import 'js_names.dart' as JS;
36 import 'js_metalet.dart' as JS; 36 import 'js_metalet.dart' as JS;
37 import 'js_module_item_order.dart'; 37 import 'js_module_item_order.dart';
38 import 'js_names.dart'; 38 import 'js_names.dart';
39 import 'js_printer.dart' show writeJsLibrary; 39 import 'js_printer.dart' show writeJsLibrary;
40 import 'side_effect_analysis.dart'; 40 import 'side_effect_analysis.dart';
41 import 'package:collection/equality.dart';
42 41
43 // Various dynamic helpers we call. 42 // Various dynamic helpers we call.
44 // If renaming these, make sure to check other places like the 43 // If renaming these, make sure to check other places like the
45 // _runtime.js file and comments. 44 // _runtime.js file and comments.
46 // TODO(jmesserly): ideally we'd have a "dynamic call" dart library we can 45 // TODO(jmesserly): ideally we'd have a "dynamic call" dart library we can
47 // import and generate calls to, rather than dart_runtime.js 46 // import and generate calls to, rather than dart_runtime.js
48 const DPUT = 'dput'; 47 const DPUT = 'dput';
49 const DLOAD = 'dload'; 48 const DLOAD = 'dload';
50 const DINDEX = 'dindex'; 49 const DINDEX = 'dindex';
51 const DSETINDEX = 'dsetindex'; 50 const DSETINDEX = 'dsetindex';
52 const DCALL = 'dcall'; 51 const DCALL = 'dcall';
53 const DSEND = 'dsend'; 52 const DSEND = 'dsend';
54 53
55 const ListEquality _listEquality = const ListEquality();
56
57 class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator { 54 class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
58 final AbstractCompiler compiler; 55 final AbstractCompiler compiler;
59 final CodegenOptions options; 56 final CodegenOptions options;
60 final TypeRules rules; 57 final TypeRules rules;
61 final LibraryElement currentLibrary; 58 final LibraryElement currentLibrary;
62 59
63 /// The global extension type table. 60 /// The global extension type table.
64 final HashSet<ClassElement> _extensionTypes; 61 final HashSet<ClassElement> _extensionTypes;
65 62
66 /// Information that is precomputed for this library, indicates which fields 63 /// Information that is precomputed for this library, indicates which fields
(...skipping 20 matching lines...) Expand all
87 final _privateNames = new HashMap<String, JS.TemporaryId>(); 84 final _privateNames = new HashMap<String, JS.TemporaryId>();
88 final _moduleItems = <JS.Statement>[]; 85 final _moduleItems = <JS.Statement>[];
89 final _temps = new HashMap<Element, JS.TemporaryId>(); 86 final _temps = new HashMap<Element, JS.TemporaryId>();
90 final _qualifiedIds = new List<Tuple2<Element, JS.MaybeQualifiedId>>(); 87 final _qualifiedIds = new List<Tuple2<Element, JS.MaybeQualifiedId>>();
91 88
92 /// The name for the library's exports inside itself. 89 /// The name for the library's exports inside itself.
93 /// `exports` was chosen as the most similar to ES module patterns. 90 /// `exports` was chosen as the most similar to ES module patterns.
94 final _dartxVar = new JS.Identifier('dartx'); 91 final _dartxVar = new JS.Identifier('dartx');
95 final _exportsVar = new JS.TemporaryId('exports'); 92 final _exportsVar = new JS.TemporaryId('exports');
96 final _runtimeLibVar = new JS.Identifier('dart'); 93 final _runtimeLibVar = new JS.Identifier('dart');
94 final _utilsLibVar = new JS.TemporaryId('utils');
95 final _classesLibVar = new JS.TemporaryId('classes');
96 final _rttiLibVar = new JS.TemporaryId('rtti');
97 final _namedArgTemp = new JS.TemporaryId('opts'); 97 final _namedArgTemp = new JS.TemporaryId('opts');
98 98
99 final TypeProvider _types; 99 final TypeProvider _types;
100 100
101 ConstFieldVisitor _constField; 101 ConstFieldVisitor _constField;
102 102
103 ModuleItemLoadOrder _loader; 103 ModuleItemLoadOrder _loader;
104 104
105 /// _interceptors.JSArray<E>, used for List literals. 105 /// _interceptors.JSArray<E>, used for List literals.
106 ClassElement _jsArray; 106 ClassElement _jsArray;
107 107
108 /// The default value of the module object. See [visitLibraryDirective]. 108 /// The default value of the module object. See [visitLibraryDirective].
109 String _jsModuleValue; 109 String _jsModuleValue;
110 110
111 bool _isDartUtils; 111 bool _isDartRuntime;
112 112
113 Map<String, DartType> _objectMembers; 113 Map<String, DartType> _objectMembers;
114 114
115 JSCodegenVisitor(AbstractCompiler compiler, this.rules, this.currentLibrary, 115 JSCodegenVisitor(AbstractCompiler compiler, this.rules, this.currentLibrary,
116 this._extensionTypes, this._fieldsNeedingStorage) 116 this._extensionTypes, this._fieldsNeedingStorage)
117 : compiler = compiler, 117 : compiler = compiler,
118 options = compiler.options.codegenOptions, 118 options = compiler.options.codegenOptions,
119 _types = compiler.context.typeProvider { 119 _types = compiler.context.typeProvider {
120 _loader = new ModuleItemLoadOrder(_emitModuleItem); 120 _loader = new ModuleItemLoadOrder(_emitModuleItem);
121 121
122 var context = compiler.context; 122 var context = compiler.context;
123 var src = context.sourceFactory.forUri('dart:_interceptors'); 123 var src = context.sourceFactory.forUri('dart:_interceptors');
124 var interceptors = context.computeLibraryElement(src); 124 var interceptors = context.computeLibraryElement(src);
125 _jsArray = interceptors.getType('JSArray'); 125 _jsArray = interceptors.getType('JSArray');
126 _isDartUtils = currentLibrary.source.uri.toString() == 'dart:_utils'; 126
127 _isDartRuntime = _runtimeLibUris.contains(_getLibUri(currentLibrary));
127 128
128 _objectMembers = getObjectMemberMap(types); 129 _objectMembers = getObjectMemberMap(types);
129 } 130 }
131 String _getLibUri(LibraryElement lib) => lib.source.uri.toString();
132
133 static final _runtimeLibUris = new Set<String>.from([
Jennifer Messerly 2016/01/07 20:18:04 ideally we wouldn't need to hard code these, or ge
ochafik 2016/01/13 13:13:20 Dropped this but kept _isDartRuntime (testing on d
134 'dart:_utils',
135 'dart:_runtime',
136 'dart:_operations',
137 'dart:_errors',
138 'dart:_classes',
139 'dart:_generators',
140 'dart:_operations',
141 'dart:_types',
142 'dart:_rtti'
143 ]);
130 144
131 TypeProvider get types => rules.provider; 145 TypeProvider get types => rules.provider;
132 146
133 JS.Program emitLibrary(LibraryUnit library) { 147 JS.Program emitLibrary(LibraryUnit library) {
134 // Modify the AST to make coercions explicit. 148 // Modify the AST to make coercions explicit.
135 new CoercionReifier(library, rules).reify(); 149 new CoercionReifier(library, rules).reify();
136 150
137 // Build the public namespace for this library. This allows us to do 151 // Build the public namespace for this library. This allows us to do
138 // constant time lookups (contrast with `Element.getChild(name)`). 152 // constant time lookups (contrast with `Element.getChild(name)`).
139 if (currentLibrary.publicNamespace == null) { 153 if (currentLibrary.publicNamespace == null) {
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 // TODO(jmesserly): make these immutable in JS? 203 // TODO(jmesserly): make these immutable in JS?
190 for (var name in _exports) { 204 for (var name in _exports) {
191 _moduleItems.add(js.statement('#.# = #;', [_exportsVar, name, name])); 205 _moduleItems.add(js.statement('#.# = #;', [_exportsVar, name, name]));
192 } 206 }
193 207
194 var jsPath = compiler.getModuleName(currentLibrary.source.uri); 208 var jsPath = compiler.getModuleName(currentLibrary.source.uri);
195 209
196 // TODO(jmesserly): it would be great to run the renamer on the body, 210 // TODO(jmesserly): it would be great to run the renamer on the body,
197 // then figure out if we really need each of these parameters. 211 // then figure out if we really need each of these parameters.
198 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34 212 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34
199 var params = [_exportsVar, _runtimeLibVar]; 213 var params = [_exportsVar];
200 var processImport = 214 var lazyParams = [];
201 (LibraryElement library, JS.TemporaryId temp, List list) {
202 params.add(temp);
203 list.add(js.string(compiler.getModuleName(library.source.uri), "'"));
204 };
205 215
206 var needsDartRuntime = !_isDartUtils; 216 var libUri = _getLibUri(currentLibrary);
207 217
208 var imports = <JS.Expression>[]; 218 var imports = <JS.Expression>[];
219 var lazyImports = <JS.Expression>[];
209 var moduleStatements = <JS.Statement>[]; 220 var moduleStatements = <JS.Statement>[];
210 if (needsDartRuntime) { 221
211 imports.add(js.string('dart/_runtime')); 222 addImport(String name, JS.Expression libVar, {bool eager: true}) {
223 (eager ? imports : lazyImports).add(js.string(name, "'"));
224 (eager ? params : lazyParams).add(libVar);
225 }
226
227 if (!_isDartRuntime) {
228 addImport('dart/_runtime', _runtimeLibVar);
Jennifer Messerly 2016/01/07 20:18:04 can we just import this library explicitly? /
ochafik 2016/01/13 13:13:20 That's mainly for the "mere mortal" files
212 229
213 var dartxImport = 230 var dartxImport =
214 js.statement("let # = #.dartx;", [_dartxVar, _runtimeLibVar]); 231 js.statement("let # = #.dartx;", [_dartxVar, _runtimeLibVar]);
215 moduleStatements.add(dartxImport); 232 moduleStatements.add(dartxImport);
233 } else {
234 if (libUri == 'dart:_generators') {
235 addImport('dart/_classes', _classesLibVar);
Jennifer Messerly 2016/01/07 20:18:04 same here, can we import this explicitly?
ochafik 2016/01/13 13:13:20 Dropped now that all runtime is in dart:_runtime
236 }
216 } 237 }
217 moduleStatements.addAll(_moduleItems); 238 moduleStatements.addAll(_moduleItems);
218 239
219 _imports.forEach((library, temp) { 240 bool shouldImportEagerly(lib) {
220 if (_loader.libraryIsLoaded(library)) { 241 var otherLibUri = _getLibUri(lib);
221 processImport(library, temp, imports); 242
222 } 243 // utils.dart contains very low-level utils and doesn't import anyone.
244 if (otherLibUri == 'dart:_utils') return true;
Jennifer Messerly 2016/01/07 20:18:05 can we just add these cases to the existing coreli
ochafik 2016/01/13 13:13:20 Ack
245 // Types in types.dart extend rtti.LazyTagged in a way that isn't
246 // recognized by the loader: we help it out here.
Jennifer Messerly 2016/01/07 20:18:04 can you explain the problem with this? I'm not fol
ochafik 2016/01/13 13:13:20 Dropped special logic
247 if (libUri == 'dart:_types' && otherLibUri == 'dart:_rtti') return true;
248 if (libUri == 'dart:_runtime') return otherLibUri != 'dart:_js_helper';
249 // runtime.dart needs to import everything but utils.dart lazily.
250 if (_isDartRuntime) return false;
251
252 return _loader.libraryIsLoaded(lib);
253 }
254
255 var importsEagerness = new Map<LibraryElement, bool>.fromIterable(
256 _imports.keys,
257 value: shouldImportEagerly);
258
259 _imports.forEach((LibraryElement lib, JS.TemporaryId temp) {
260 bool eager = importsEagerness[lib];
261 addImport(compiler.getModuleName(lib.source.uri), temp, eager: eager);
223 }); 262 });
224 263
225 var lazyImports = <JS.Expression>[]; 264 params.addAll(lazyParams);
226 _imports.forEach((library, temp) {
227 if (!_loader.libraryIsLoaded(library)) {
228 processImport(library, temp, lazyImports);
229 }
230 });
231 265
232 var module = 266 var module =
233 js.call("function(#) { 'use strict'; #; }", [params, moduleStatements]); 267 js.call("function(#) { 'use strict'; #; }", [params, moduleStatements]);
234 268
235 var moduleDef = js.statement("dart_library.library(#, #, #, #, #)", [ 269 var moduleDef = js.statement("dart_library.library(#, #, #, #, #)", [
236 js.string(jsPath, "'"), 270 js.string(jsPath, "'"),
237 _jsModuleValue ?? new JS.LiteralNull(), 271 _jsModuleValue ?? new JS.LiteralNull(),
238 js.commentExpression( 272 js.commentExpression(
239 "Imports", new JS.ArrayInitializer(imports, multiline: true)), 273 "Imports", new JS.ArrayInitializer(imports, multiline: true)),
240 js.commentExpression("Lazy imports", 274 js.commentExpression("Lazy imports",
(...skipping 16 matching lines...) Expand all
257 if (node is! FunctionDeclaration) _flushLibraryProperties(_moduleItems); 291 if (node is! FunctionDeclaration) _flushLibraryProperties(_moduleItems);
258 292
259 var code = _visit(node); 293 var code = _visit(node);
260 if (code != null) _moduleItems.add(code); 294 if (code != null) _moduleItems.add(code);
261 } 295 }
262 296
263 @override 297 @override
264 void visitLibraryDirective(LibraryDirective node) { 298 void visitLibraryDirective(LibraryDirective node) {
265 assert(_jsModuleValue == null); 299 assert(_jsModuleValue == null);
266 300
267 var jsName = findAnnotation(node.element, isJSAnnotation); 301 _jsModuleValue = _getJsName(node.element);
268 _jsModuleValue = 302 }
269 getConstantField(jsName, 'name', types.stringType)?.toStringValue(); 303
304 String _getJsName(Element e) {
Jennifer Messerly 2016/01/07 20:18:04 I'm a little confused about this function. It coul
ochafik 2016/01/13 13:13:20 Spun this out in https://codereview.chromium.org/1
305 var jsName = findAnnotation(e, isJSAnnotation);
306 return getConstantField(jsName, 'name', types.stringType)?.toStringValue();
270 } 307 }
271 308
272 @override 309 @override
273 void visitImportDirective(ImportDirective node) { 310 void visitImportDirective(ImportDirective node) {
274 // Nothing to do yet, but we'll want to convert this to an ES6 import once 311 // Nothing to do yet, but we'll want to convert this to an ES6 import once
275 // we have support for modules. 312 // we have support for modules.
276 } 313 }
277 314
278 @override void visitPartDirective(PartDirective node) {} 315 @override void visitPartDirective(PartDirective node) {}
279 @override void visitPartOfDirective(PartOfDirective node) {} 316 @override void visitPartOfDirective(PartOfDirective node) {}
280 317
281 @override 318 @override
282 void visitExportDirective(ExportDirective node) { 319 void visitExportDirective(ExportDirective node) {
283 var exportName = _libraryName(node.uriElement); 320 var exportName = _libraryName(node.uriElement);
284 321
285 var currentLibNames = currentLibrary.publicNamespace.definedNames; 322 var currentLibNames = currentLibrary.publicNamespace.definedNames;
286 323
287 var args = [_exportsVar, exportName]; 324 var args = [_exportsVar, exportName];
288 if (node.combinators.isNotEmpty) { 325 if (node.combinators.isNotEmpty) {
289 var shownNames = <JS.Expression>[]; 326 var shownNames = <JS.Expression>[];
290 var hiddenNames = <JS.Expression>[]; 327 var hiddenNames = <JS.Expression>[];
291 328
292 var show = node.combinators.firstWhere((c) => c is ShowCombinator, 329 var show = node.combinators.firstWhere((c) => c is ShowCombinator,
293 orElse: () => null) as ShowCombinator; 330 orElse: () => null) as ShowCombinator;
294 var hide = node.combinators.firstWhere((c) => c is HideCombinator, 331 var hide = node.combinators.firstWhere((c) => c is HideCombinator,
295 orElse: () => null) as HideCombinator; 332 orElse: () => null) as HideCombinator;
296 if (show != null) { 333 if (show != null) {
334 // If the import has a single shown name + a JsName(jsName) annotation,
335 // then we use that jsName as the exported name.
336 var singleJsName = _getJsName(node.element);
337 if (singleJsName != null && show.shownNames.length != 1) {
338 throw new StateError('Cannot set js name on more than one export');
Jennifer Messerly 2016/01/07 20:18:04 Can this error be triggered by user code? If so,
ochafik 2016/01/13 13:13:20 Dropped that (no need to re-export anymore with th
339 }
297 shownNames.addAll(show.shownNames 340 shownNames.addAll(show.shownNames
298 .map((i) => i.name) 341 .map((i) => singleJsName ?? i.name)
299 .where((s) => !currentLibNames.containsKey(s)) 342 .where((s) => !currentLibNames.containsKey(s))
300 .map((s) => js.string(s, "'"))); 343 .map((s) => js.string(s, "'")));
301 } 344 }
302 if (hide != null) { 345 if (hide != null) {
303 hiddenNames.addAll(hide.hiddenNames.map((i) => js.string(i.name, "'"))); 346 hiddenNames.addAll(hide.hiddenNames.map((i) => js.string(i.name, "'")));
304 } 347 }
305 args.add(new JS.ArrayInitializer(shownNames)); 348 args.add(new JS.ArrayInitializer(shownNames));
306 args.add(new JS.ArrayInitializer(hiddenNames)); 349 args.add(new JS.ArrayInitializer(hiddenNames));
307 } 350 }
308 _moduleItems.add(js.statement('dart.export_(#);', [args])); 351
352 // When we compile _runtime.js, we need to source export_ from _utils.js:
353 _moduleItems.add(js.statement('#(#);', [_dartExport, args]));
309 } 354 }
310 355
311 JS.Identifier _initSymbol(JS.Identifier id) { 356 JS.Identifier _initSymbol(JS.Identifier id) {
312 var s = 357 var s =
313 js.statement('const # = $_SYMBOL(#);', [id, js.string(id.name, "'")]); 358 js.statement('const # = $_SYMBOL(#);', [id, js.string(id.name, "'")]);
314 _moduleItems.add(s); 359 _moduleItems.add(s);
315 return id; 360 return id;
316 } 361 }
317 362
318 // TODO(jmesserly): this is a temporary workaround for `Symbol` in core, 363 // TODO(jmesserly): this is a temporary workaround for `Symbol` in core,
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after
572 return js.statement('{ #; let # = #; }', [genericDef, name, genericInst]); 617 return js.statement('{ #; let # = #; }', [genericDef, name, genericInst]);
573 } 618 }
574 return body; 619 return body;
575 } 620 }
576 621
577 JS.Statement _emitGenericClassDef(ParameterizedType type, JS.Statement body) { 622 JS.Statement _emitGenericClassDef(ParameterizedType type, JS.Statement body) {
578 var name = type.name; 623 var name = type.name;
579 var genericName = '$name\$'; 624 var genericName = '$name\$';
580 var typeParams = type.typeParameters.map((p) => p.name); 625 var typeParams = type.typeParameters.map((p) => p.name);
581 if (isPublic(name)) _exports.add(genericName); 626 if (isPublic(name)) _exports.add(genericName);
582 return js.statement('const # = dart.generic(function(#) { #; return #; });', 627
583 [genericName, typeParams, body, name]); 628 return js.statement('const # = #(function(#) { #; return #; });',
629 [genericName, _dartGeneric, typeParams, body, name]);
584 } 630 }
585 631
632 get _dartGeneric =>
633 js.call('#.generic', [_isDartRuntime ? _classesLibVar : _runtimeLibVar]);
Jennifer Messerly 2016/01/07 20:18:05 I made this comment elsewhere, but I don't think w
ochafik 2016/01/13 13:13:20 Parts FTW!
634
635 get _dartExport =>
636 js.call('#.export', [_isDartRuntime ? _utilsLibVar : _runtimeLibVar]);
637
638 get _dartFn => js.call('#.fn', _isDartRuntime ? _rttiLibVar : _runtimeLibVar);
639
640 get _dartSetSignature => js.call(
641 '#.setSignature', [_isDartRuntime ? _classesLibVar : _runtimeLibVar]);
642
586 final _hasDeferredSupertype = new HashSet<ClassElement>(); 643 final _hasDeferredSupertype = new HashSet<ClassElement>();
587 644
588 bool _deferIfNeeded(DartType type, ClassElement current) { 645 bool _deferIfNeeded(DartType type, ClassElement current) {
589 if (type is ParameterizedType) { 646 if (type is ParameterizedType) {
590 var typeArguments = type.typeArguments; 647 var typeArguments = type.typeArguments;
591 for (var typeArg in typeArguments) { 648 for (var typeArg in typeArguments) {
592 var typeElement = typeArg.element; 649 var typeElement = typeArg.element;
593 // FIXME(vsm): This does not track mutual recursive dependences. 650 // FIXME(vsm): This does not track mutual recursive dependences.
594 if (current == typeElement || _deferIfNeeded(typeArg, current)) { 651 if (current == typeElement || _deferIfNeeded(typeArg, current)) {
595 return true; 652 return true;
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after
825 if (!tStatics.isEmpty) { 882 if (!tStatics.isEmpty) {
826 assert(!sNames.isEmpty); 883 assert(!sNames.isEmpty);
827 var aNames = new JS.Property( 884 var aNames = new JS.Property(
828 _propertyName('names'), new JS.ArrayInitializer(sNames)); 885 _propertyName('names'), new JS.ArrayInitializer(sNames));
829 sigFields.add(build('statics', tStatics)); 886 sigFields.add(build('statics', tStatics));
830 sigFields.add(aNames); 887 sigFields.add(aNames);
831 } 888 }
832 if (!sigFields.isEmpty || extensions.isNotEmpty) { 889 if (!sigFields.isEmpty || extensions.isNotEmpty) {
833 var sig = new JS.ObjectInitializer(sigFields); 890 var sig = new JS.ObjectInitializer(sigFields);
834 var classExpr = new JS.Identifier(name); 891 var classExpr = new JS.Identifier(name);
835 body.add(js.statement('dart.setSignature(#, #);', [classExpr, sig])); 892 body.add(js.statement('#(#, #);', [_dartSetSignature, classExpr, sig]));
836 } 893 }
837 } 894 }
838 895
839 // If a concrete class implements one of our extensions, we might need to 896 // If a concrete class implements one of our extensions, we might need to
840 // add forwarders. 897 // add forwarders.
841 if (extensions.isNotEmpty) { 898 if (extensions.isNotEmpty) {
842 var methodNames = <JS.Expression>[]; 899 var methodNames = <JS.Expression>[];
843 for (var e in extensions) { 900 for (var e in extensions) {
844 methodNames.add(_elementMemberName(e)); 901 methodNames.add(_elementMemberName(e));
845 } 902 }
(...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after
1298 1355
1299 if (node.isGetter || node.isSetter) { 1356 if (node.isGetter || node.isSetter) {
1300 // Add these later so we can use getter/setter syntax. 1357 // Add these later so we can use getter/setter syntax.
1301 _properties.add(node); 1358 _properties.add(node);
1302 return null; 1359 return null;
1303 } 1360 }
1304 1361
1305 var body = <JS.Statement>[]; 1362 var body = <JS.Statement>[];
1306 _flushLibraryProperties(body); 1363 _flushLibraryProperties(body);
1307 1364
1308 var name = node.name.name; 1365 var name = _getJsName(node.element) ?? node.name.name;
1309 1366
1310 var fn = _visit(node.functionExpression); 1367 var fn = _visit(node.functionExpression);
1311 bool needsTagging = true; 1368 // Don't tag functions defined in the low-level runtime.
1369 bool needsTagging = !_isDartRuntime;
1312 1370
1313 if (currentLibrary.source.isInSystemLibrary && 1371 if (currentLibrary.source.isInSystemLibrary &&
1314 _isInlineJSFunction(node.functionExpression)) { 1372 _isInlineJSFunction(node.functionExpression)) {
1315 fn = _simplifyPassThroughArrowFunCallBody(fn); 1373 fn = _simplifyPassThroughArrowFunCallBody(fn);
1316 needsTagging = !_isDartUtils;
1317 } 1374 }
1318 1375
1319 var id = new JS.Identifier(name); 1376 var id = new JS.Identifier(name);
1320 body.add(annotate(new JS.FunctionDeclaration(id, fn), node.element)); 1377 body.add(annotate(new JS.FunctionDeclaration(id, fn), node.element));
1321 if (needsTagging) { 1378 if (needsTagging) {
1322 body.add(_emitFunctionTagged(id, node.element.type, topLevel: true) 1379 body.add(_emitFunctionTagged(id, node.element.type, topLevel: true)
1323 .toStatement()); 1380 .toStatement());
1324 } 1381 }
1325 1382
1326 if (isPublic(name)) _addExport(name); 1383 if (isPublic(name)) _addExport(name);
(...skipping 11 matching lines...) Expand all
1338 return _isJSInvocation(stat.expression); 1395 return _isJSInvocation(stat.expression);
1339 } 1396 }
1340 } 1397 }
1341 } 1398 }
1342 return false; 1399 return false;
1343 } 1400 }
1344 1401
1345 bool _isJSInvocation(Expression expr) => 1402 bool _isJSInvocation(Expression expr) =>
1346 expr is MethodInvocation && isInlineJS(expr.methodName.staticElement); 1403 expr is MethodInvocation && isInlineJS(expr.methodName.staticElement);
1347 1404
1348 // Simplify `(args) => ((x, y) => { ... })(x, y)` to `(args) => { ... }`. 1405 // Simplify `(args) => (() => { ... })()` to `(args) => { ... }`.
1349 // Note: we don't check if the top-level args match the ones passed through 1406 // Note: this allows silently passing args through to the body, which only
Jennifer Messerly 2016/01/07 20:18:05 I don't think you need the "Note" anymore?
ochafik 2016/01/13 13:13:20 Done.
1350 // the arrow function, which allows silently passing args through to the 1407 // works if we don't do weird renamings of Dart params.
1351 // body (which only works if we don't do weird renamings of Dart params).
1352 JS.Fun _simplifyPassThroughArrowFunCallBody(JS.Fun fn) { 1408 JS.Fun _simplifyPassThroughArrowFunCallBody(JS.Fun fn) {
1353 String getIdent(JS.Node node) => node is JS.Identifier ? node.name : null;
1354 List<String> getIdents(List params) =>
1355 params.map(getIdent).toList(growable: false);
1356
1357 if (fn.body is JS.Block && fn.body.statements.length == 1) { 1409 if (fn.body is JS.Block && fn.body.statements.length == 1) {
1358 var stat = fn.body.statements.single; 1410 var stat = fn.body.statements.single;
1359 if (stat is JS.Return && stat.value is JS.Call) { 1411 if (stat is JS.Return && stat.value is JS.Call) {
1360 JS.Call call = stat.value; 1412 JS.Call call = stat.value;
1361 if (call.target is JS.ArrowFun) { 1413 if (call.target is JS.ArrowFun && call.arguments.isEmpty) {
1362 var passedArgs = getIdents(call.arguments);
1363 JS.ArrowFun innerFun = call.target; 1414 JS.ArrowFun innerFun = call.target;
1364 if (_listEquality.equals(getIdents(innerFun.params), passedArgs)) { 1415 if (innerFun.params.isEmpty) {
1365 return new JS.Fun(fn.params, innerFun.body); 1416 return new JS.Fun(fn.params, innerFun.body);
1366 } 1417 }
1367 } 1418 }
1368 } 1419 }
1369 } 1420 }
1370 return fn; 1421 return fn;
1371 } 1422 }
1372 1423
1373 JS.Method _emitTopLevelProperty(FunctionDeclaration node) { 1424 JS.Method _emitTopLevelProperty(FunctionDeclaration node) {
1374 var name = node.name.name; 1425 var name = node.name.name;
(...skipping 27 matching lines...) Expand all
1402 JS.Expression _emitFunctionTagged(JS.Expression clos, DartType type, 1453 JS.Expression _emitFunctionTagged(JS.Expression clos, DartType type,
1403 {topLevel: false}) { 1454 {topLevel: false}) {
1404 var name = type.name; 1455 var name = type.name;
1405 var lazy = topLevel && !_typeIsLoaded(type); 1456 var lazy = topLevel && !_typeIsLoaded(type);
1406 1457
1407 if (type is FunctionType && (name == '' || name == null)) { 1458 if (type is FunctionType && (name == '' || name == null)) {
1408 if (type.returnType.isDynamic && 1459 if (type.returnType.isDynamic &&
1409 type.optionalParameterTypes.isEmpty && 1460 type.optionalParameterTypes.isEmpty &&
1410 type.namedParameterTypes.isEmpty && 1461 type.namedParameterTypes.isEmpty &&
1411 type.normalParameterTypes.every((t) => t.isDynamic)) { 1462 type.normalParameterTypes.every((t) => t.isDynamic)) {
1412 return js.call('dart.fn(#)', [clos]); 1463 return js.call('#(#)', [_dartFn, clos]);
1413 } 1464 }
1414 if (lazy) { 1465 if (lazy) {
1415 return js.call('dart.fn(#, () => #)', [clos, _emitFunctionRTTI(type)]); 1466 return js.call(
1467 '#(#, () => #)', [_dartFn, clos, _emitFunctionRTTI(type)]);
1416 } 1468 }
1417 return js.call('dart.fn(#, #)', [clos, _emitFunctionTypeParts(type)]); 1469 return js.call('#(#, #)', [_dartFn, clos, _emitFunctionTypeParts(type)]);
1418 } 1470 }
1419 throw 'Function has non function type: $type'; 1471 throw 'Function has non function type: $type';
1420 } 1472 }
1421 1473
1422 @override 1474 @override
1423 JS.Expression visitFunctionExpression(FunctionExpression node) { 1475 JS.Expression visitFunctionExpression(FunctionExpression node) {
1424 var params = _visit(node.parameters) as List<JS.Parameter>; 1476 var params = _visit(node.parameters) as List<JS.Parameter>;
1425 if (params == null) params = <JS.Parameter>[]; 1477 if (params == null) params = <JS.Parameter>[];
1426 1478
1427 var parent = node.parent; 1479 var parent = node.parent;
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
1562 'Unimplemented unknown name', new JS.Identifier(node.name)); 1614 'Unimplemented unknown name', new JS.Identifier(node.name));
1563 } 1615 }
1564 1616
1565 // Get the original declaring element. If we had a property accessor, this 1617 // Get the original declaring element. If we had a property accessor, this
1566 // indirects back to a (possibly synthetic) field. 1618 // indirects back to a (possibly synthetic) field.
1567 var element = accessor; 1619 var element = accessor;
1568 if (accessor is PropertyAccessorElement) element = accessor.variable; 1620 if (accessor is PropertyAccessorElement) element = accessor.variable;
1569 1621
1570 _loader.declareBeforeUse(element); 1622 _loader.declareBeforeUse(element);
1571 1623
1572 var name = element.name; 1624 var name = _getJsName(element) ?? element.name;
Jennifer Messerly 2016/01/07 20:18:04 This is related to my other comment on _getJsName,
ochafik 2016/01/13 13:13:20 Moved the exported name resolution logic to down t
1573 1625
1574 // type literal 1626 // type literal
1575 if (element is ClassElement || 1627 if (element is ClassElement ||
1576 element is DynamicElementImpl || 1628 element is DynamicElementImpl ||
1577 element is FunctionTypeAliasElement) { 1629 element is FunctionTypeAliasElement) {
1578 return _emitTypeName( 1630 return _emitTypeName(
1579 fillDynamicTypeArgs((element as dynamic).type, types)); 1631 fillDynamicTypeArgs((element as dynamic).type, types));
1580 } 1632 }
1581 1633
1582 // library member 1634 // library member
1583 if (element.enclosingElement is CompilationUnitElement) { 1635 if (element.enclosingElement is CompilationUnitElement) {
1584 return _maybeQualifiedName(element); 1636 return _maybeQualifiedName(element, name);
1585 } 1637 }
1586 1638
1587 // Unqualified class member. This could mean implicit-this, or implicit 1639 // Unqualified class member. This could mean implicit-this, or implicit
1588 // call to a static from the same class. 1640 // call to a static from the same class.
1589 if (element is ClassMemberElement && element is! ConstructorElement) { 1641 if (element is ClassMemberElement && element is! ConstructorElement) {
1590 bool isStatic = element.isStatic; 1642 bool isStatic = element.isStatic;
1591 var type = element.enclosingElement.type; 1643 var type = element.enclosingElement.type;
1592 var member = _emitMemberName(name, isStatic: isStatic, type: type); 1644 var member = _emitMemberName(name, isStatic: isStatic, type: type);
1593 1645
1594 // For static methods, we add the raw type name, without generics or 1646 // For static methods, we add the raw type name, without generics or
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after
1877 var stmts = _visitList(node.block.statements) as List<JS.Statement>; 1929 var stmts = _visitList(node.block.statements) as List<JS.Statement>;
1878 if (initArgs != null) stmts.insert(0, initArgs); 1930 if (initArgs != null) stmts.insert(0, initArgs);
1879 return new JS.Block(stmts); 1931 return new JS.Block(stmts);
1880 } 1932 }
1881 1933
1882 @override 1934 @override
1883 JS.Block visitBlock(Block node) => 1935 JS.Block visitBlock(Block node) =>
1884 new JS.Block(_visitList(node.statements) as List<JS.Statement>, 1936 new JS.Block(_visitList(node.statements) as List<JS.Statement>,
1885 isScope: true); 1937 isScope: true);
1886 1938
1939 /// Return the type constructor `_foolib.Bar$` given `Bar` from lib `_foolib`.
1940 ///
1941 /// This implements / expands the `genericTypeConstructor` intrinsic defined
1942 /// in `foreign_helper.dart`.
1943 JS.Expression _emitGenericTypeConstructor(Expression typeExpression) {
Jennifer Messerly 2016/01/07 20:18:04 I don't understand why this is needed. Given a typ
ochafik 2016/01/13 13:13:20 This implements the new intrinsic used in the foll
1944 var ref = _visit(typeExpression);
1945 if (ref is JS.PropertyAccess) {
1946 var name = (ref.selector as JS.LiteralString).valueWithoutQuotes;
1947 return new JS.PropertyAccess(
1948 ref.receiver, new JS.LiteralString("'$name\$'"));
1949 } else if (ref is JS.MaybeQualifiedId) {
1950 var name = (ref.name as JS.Identifier).name;
1951 return new JS.PropertyAccess(ref.qualifier, new JS.Identifier('$name\$'));
1952 } else {
1953 throw new ArgumentError('Invalid type ref: $ref (${ref?.runtimeType})');
1954 }
1955 }
1956
1887 @override 1957 @override
1888 visitMethodInvocation(MethodInvocation node) { 1958 visitMethodInvocation(MethodInvocation node) {
1889 if (node.operator != null && node.operator.lexeme == '?.') { 1959 if (node.operator != null && node.operator.lexeme == '?.') {
1890 return _emitNullSafe(node); 1960 return _emitNullSafe(node);
1891 } 1961 }
1962 if (isGenericTypeConstructorInvocation(node)) {
1963 return _emitGenericTypeConstructor(node.argumentList.arguments.single);
Jennifer Messerly 2016/01/07 20:18:04 I don't understand why this case is needed. It see
ochafik 2016/01/13 13:13:20 Sorry for the lacking doc, this is a new intrinsic
1964 }
1892 1965
1893 var target = _getTarget(node); 1966 var target = _getTarget(node);
1894 var result = _emitForeignJS(node); 1967 var result = _emitForeignJS(node);
1895 if (result != null) return result; 1968 if (result != null) return result;
1896 1969
1897 String code; 1970 String code;
1898 if (target == null || isLibraryPrefix(target)) { 1971 if (target == null || isLibraryPrefix(target)) {
1899 if (DynamicInvoke.get(node.methodName)) { 1972 if (DynamicInvoke.get(node.methodName)) {
1900 code = 'dart.$DCALL(#, #)'; 1973 code = 'dart.$DCALL(#, #)';
1901 } else { 1974 } else {
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after
2207 } else { 2280 } else {
2208 jsInit = _visitInitializer(field); 2281 jsInit = _visitInitializer(field);
2209 eagerInit = false; 2282 eagerInit = false;
2210 } 2283 }
2211 2284
2212 // Treat `final x = JS('', '...')` as a const (non-lazy) to help compile 2285 // Treat `final x = JS('', '...')` as a const (non-lazy) to help compile
2213 // runtime helpers. 2286 // runtime helpers.
2214 var isJSTopLevel = field.isFinal && _isFinalJSDecl(field); 2287 var isJSTopLevel = field.isFinal && _isFinalJSDecl(field);
2215 if (isJSTopLevel) eagerInit = true; 2288 if (isJSTopLevel) eagerInit = true;
2216 2289
2217 var fieldName = field.name.name; 2290 var fieldName = _getJsName(element) ?? field.name.name;
2291
2218 if ((field.isConst && eagerInit && element is TopLevelVariableElement) || 2292 if ((field.isConst && eagerInit && element is TopLevelVariableElement) ||
2219 isJSTopLevel) { 2293 isJSTopLevel) {
2220 // constant fields don't change, so we can generate them as `let` 2294 // constant fields don't change, so we can generate them as `let`
2221 // but add them to the module's exports. However, make sure we generate 2295 // but add them to the module's exports. However, make sure we generate
2222 // anything they depend on first. 2296 // anything they depend on first.
2223 2297
2224 if (isPublic(fieldName)) _addExport(fieldName); 2298 if (isPublic(fieldName)) _addExport(fieldName);
2225 var declKeyword = field.isConst || field.isFinal ? 'const' : 'let'; 2299 var declKeyword = field.isConst || field.isFinal ? 'const' : 'let';
2226 return annotateVariable( 2300 return annotateVariable(
2227 js.statement( 2301 js.statement(
(...skipping 615 matching lines...) Expand 10 before | Expand all | Expand 10 after
2843 } 2917 }
2844 2918
2845 String code; 2919 String code;
2846 if (member != null && member is MethodElement && !isStatic) { 2920 if (member != null && member is MethodElement && !isStatic) {
2847 // Tear-off methods: explicitly bind it. 2921 // Tear-off methods: explicitly bind it.
2848 if (target is SuperExpression) { 2922 if (target is SuperExpression) {
2849 return js.call('dart.bind(this, #, #.#)', [name, _visit(target), name]); 2923 return js.call('dart.bind(this, #, #.#)', [name, _visit(target), name]);
2850 } else if (_requiresStaticDispatch(target, memberId.name)) { 2924 } else if (_requiresStaticDispatch(target, memberId.name)) {
2851 var type = member.type; 2925 var type = member.type;
2852 var clos = js.call('dart.#.bind(#)', [name, _visit(target)]); 2926 var clos = js.call('dart.#.bind(#)', [name, _visit(target)]);
2853 return js.call('dart.fn(#, #)', [clos, _emitFunctionTypeParts(type)]); 2927 return js.call(
2928 '#(#, #)', [_dartFn, clos, _emitFunctionTypeParts(type)]);
2854 } 2929 }
2855 code = 'dart.bind(#, #)'; 2930 code = 'dart.bind(#, #)';
2856 } else if (_requiresStaticDispatch(target, memberId.name)) { 2931 } else if (_requiresStaticDispatch(target, memberId.name)) {
2857 return js.call('dart.#(#)', [name, _visit(target)]); 2932 return js.call('dart.#(#)', [name, _visit(target)]);
2858 } else { 2933 } else {
2859 code = '#.#'; 2934 code = '#.#';
2860 } 2935 }
2861 2936
2862 return js.call(code, [_visit(target), name]); 2937 return js.call(code, [_visit(target), name]);
2863 } 2938 }
(...skipping 548 matching lines...) Expand 10 before | Expand all | Expand 10 after
3412 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; 3487 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody;
3413 3488
3414 FunctionBody _functionBody(node) => 3489 FunctionBody _functionBody(node) =>
3415 node is FunctionDeclaration ? node.functionExpression.body : node.body; 3490 node is FunctionDeclaration ? node.functionExpression.body : node.body;
3416 3491
3417 /// Choose a canonical name from the library element. 3492 /// Choose a canonical name from the library element.
3418 /// This never uses the library's name (the identifier in the `library` 3493 /// This never uses the library's name (the identifier in the `library`
3419 /// declaration) as it doesn't have any meaningful rules enforced. 3494 /// declaration) as it doesn't have any meaningful rules enforced.
3420 JS.Identifier _libraryName(LibraryElement library) { 3495 JS.Identifier _libraryName(LibraryElement library) {
3421 if (library == currentLibrary) return _exportsVar; 3496 if (library == currentLibrary) return _exportsVar;
3422 return _imports.putIfAbsent( 3497 return _imports.putIfAbsent(library, () {
3423 library, () => new JS.TemporaryId(jsLibraryName(library))); 3498 var name = library.name;
3499 if (name == 'dart._utils') return _utilsLibVar;
Jennifer Messerly 2016/01/07 20:18:04 I don't think these special cases could be needed.
ochafik 2016/01/13 13:13:20 Done.
3500 else if (name == 'dart._classes') return _classesLibVar;
Jennifer Messerly 2016/01/07 20:18:04 also, relying on the library name is super risky.
ochafik 2016/01/13 13:13:20 Acknowledged.
3501 else if (name == 'dart._rtti') return _rttiLibVar;
3502 else return new JS.TemporaryId(jsLibraryName(library));
3503 });
3424 } 3504 }
3425 3505
3426 DartType getStaticType(Expression e) => rules.getStaticType(e); 3506 DartType getStaticType(Expression e) => rules.getStaticType(e);
3427 3507
3428 @override 3508 @override
3429 String getQualifiedName(TypeDefiningElement type) { 3509 String getQualifiedName(TypeDefiningElement type) {
3430 JS.TemporaryId id = _imports[type.library]; 3510 JS.TemporaryId id = _imports[type.library];
3431 return id == null ? type.name : '${id.name}.${type.name}'; 3511 return id == null ? type.name : '${id.name}.${type.name}';
3432 } 3512 }
3433 3513
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
3524 3604
3525 /// A special kind of element created by the compiler, signifying a temporary 3605 /// A special kind of element created by the compiler, signifying a temporary
3526 /// variable. These objects use instance equality, and should be shared 3606 /// variable. These objects use instance equality, and should be shared
3527 /// everywhere in the tree where they are treated as the same variable. 3607 /// everywhere in the tree where they are treated as the same variable.
3528 class TemporaryVariableElement extends LocalVariableElementImpl { 3608 class TemporaryVariableElement extends LocalVariableElementImpl {
3529 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); 3609 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name);
3530 3610
3531 int get hashCode => identityHashCode(this); 3611 int get hashCode => identityHashCode(this);
3532 bool operator ==(Object other) => identical(this, other); 3612 bool operator ==(Object other) => identical(this, other);
3533 } 3613 }
OLDNEW
« no previous file with comments | « lib/runtime/dart/html_common.js ('k') | lib/src/codegen/js_interop.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698