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

Unified 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/src/codegen/js_codegen.dart
diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart
index 1ca3993e1a8c9303368e813f868f5389a17da4ea..e2bb50047502b2e78f5abe54d1862de01e92e131 100644
--- a/lib/src/codegen/js_codegen.dart
+++ b/lib/src/codegen/js_codegen.dart
@@ -38,7 +38,6 @@ import 'js_module_item_order.dart';
import 'js_names.dart';
import 'js_printer.dart' show writeJsLibrary;
import 'side_effect_analysis.dart';
-import 'package:collection/equality.dart';
// Various dynamic helpers we call.
// If renaming these, make sure to check other places like the
@@ -52,8 +51,6 @@ const DSETINDEX = 'dsetindex';
const DCALL = 'dcall';
const DSEND = 'dsend';
-const ListEquality _listEquality = const ListEquality();
-
class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
final AbstractCompiler compiler;
final CodegenOptions options;
@@ -94,6 +91,9 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
final _dartxVar = new JS.Identifier('dartx');
final _exportsVar = new JS.TemporaryId('exports');
final _runtimeLibVar = new JS.Identifier('dart');
+ final _utilsLibVar = new JS.TemporaryId('utils');
+ final _classesLibVar = new JS.TemporaryId('classes');
+ final _rttiLibVar = new JS.TemporaryId('rtti');
final _namedArgTemp = new JS.TemporaryId('opts');
final TypeProvider _types;
@@ -108,7 +108,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
/// The default value of the module object. See [visitLibraryDirective].
String _jsModuleValue;
- bool _isDartUtils;
+ bool _isDartRuntime;
Map<String, DartType> _objectMembers;
@@ -123,10 +123,24 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
var src = context.sourceFactory.forUri('dart:_interceptors');
var interceptors = context.computeLibraryElement(src);
_jsArray = interceptors.getType('JSArray');
- _isDartUtils = currentLibrary.source.uri.toString() == 'dart:_utils';
+
+ _isDartRuntime = _runtimeLibUris.contains(_getLibUri(currentLibrary));
_objectMembers = getObjectMemberMap(types);
}
+ String _getLibUri(LibraryElement lib) => lib.source.uri.toString();
+
+ 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
+ 'dart:_utils',
+ 'dart:_runtime',
+ 'dart:_operations',
+ 'dart:_errors',
+ 'dart:_classes',
+ 'dart:_generators',
+ 'dart:_operations',
+ 'dart:_types',
+ 'dart:_rtti'
+ ]);
TypeProvider get types => rules.provider;
@@ -196,39 +210,59 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
// TODO(jmesserly): it would be great to run the renamer on the body,
// then figure out if we really need each of these parameters.
// See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34
- var params = [_exportsVar, _runtimeLibVar];
- var processImport =
- (LibraryElement library, JS.TemporaryId temp, List list) {
- params.add(temp);
- list.add(js.string(compiler.getModuleName(library.source.uri), "'"));
- };
+ var params = [_exportsVar];
+ var lazyParams = [];
- var needsDartRuntime = !_isDartUtils;
+ var libUri = _getLibUri(currentLibrary);
var imports = <JS.Expression>[];
+ var lazyImports = <JS.Expression>[];
var moduleStatements = <JS.Statement>[];
- if (needsDartRuntime) {
- imports.add(js.string('dart/_runtime'));
+
+ addImport(String name, JS.Expression libVar, {bool eager: true}) {
+ (eager ? imports : lazyImports).add(js.string(name, "'"));
+ (eager ? params : lazyParams).add(libVar);
+ }
+
+ if (!_isDartRuntime) {
+ 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
var dartxImport =
js.statement("let # = #.dartx;", [_dartxVar, _runtimeLibVar]);
moduleStatements.add(dartxImport);
+ } else {
+ if (libUri == 'dart:_generators') {
+ 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
+ }
}
moduleStatements.addAll(_moduleItems);
- _imports.forEach((library, temp) {
- if (_loader.libraryIsLoaded(library)) {
- processImport(library, temp, imports);
- }
- });
+ bool shouldImportEagerly(lib) {
+ var otherLibUri = _getLibUri(lib);
- var lazyImports = <JS.Expression>[];
- _imports.forEach((library, temp) {
- if (!_loader.libraryIsLoaded(library)) {
- processImport(library, temp, lazyImports);
- }
+ // utils.dart contains very low-level utils and doesn't import anyone.
+ 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
+ // Types in types.dart extend rtti.LazyTagged in a way that isn't
+ // 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
+ if (libUri == 'dart:_types' && otherLibUri == 'dart:_rtti') return true;
+ if (libUri == 'dart:_runtime') return otherLibUri != 'dart:_js_helper';
+ // runtime.dart needs to import everything but utils.dart lazily.
+ if (_isDartRuntime) return false;
+
+ return _loader.libraryIsLoaded(lib);
+ }
+
+ var importsEagerness = new Map<LibraryElement, bool>.fromIterable(
+ _imports.keys,
+ value: shouldImportEagerly);
+
+ _imports.forEach((LibraryElement lib, JS.TemporaryId temp) {
+ bool eager = importsEagerness[lib];
+ addImport(compiler.getModuleName(lib.source.uri), temp, eager: eager);
});
+ params.addAll(lazyParams);
+
var module =
js.call("function(#) { 'use strict'; #; }", [params, moduleStatements]);
@@ -264,9 +298,12 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
void visitLibraryDirective(LibraryDirective node) {
assert(_jsModuleValue == null);
- var jsName = findAnnotation(node.element, isJSAnnotation);
- _jsModuleValue =
- getConstantField(jsName, 'name', types.stringType)?.toStringValue();
+ _jsModuleValue = _getJsName(node.element);
+ }
+
+ 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
+ var jsName = findAnnotation(e, isJSAnnotation);
+ return getConstantField(jsName, 'name', types.stringType)?.toStringValue();
}
@override
@@ -294,8 +331,14 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
var hide = node.combinators.firstWhere((c) => c is HideCombinator,
orElse: () => null) as HideCombinator;
if (show != null) {
+ // If the import has a single shown name + a JsName(jsName) annotation,
+ // then we use that jsName as the exported name.
+ var singleJsName = _getJsName(node.element);
+ if (singleJsName != null && show.shownNames.length != 1) {
+ 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
+ }
shownNames.addAll(show.shownNames
- .map((i) => i.name)
+ .map((i) => singleJsName ?? i.name)
.where((s) => !currentLibNames.containsKey(s))
.map((s) => js.string(s, "'")));
}
@@ -305,7 +348,9 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
args.add(new JS.ArrayInitializer(shownNames));
args.add(new JS.ArrayInitializer(hiddenNames));
}
- _moduleItems.add(js.statement('dart.export_(#);', [args]));
+
+ // When we compile _runtime.js, we need to source export_ from _utils.js:
+ _moduleItems.add(js.statement('#(#);', [_dartExport, args]));
}
JS.Identifier _initSymbol(JS.Identifier id) {
@@ -579,10 +624,22 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
var genericName = '$name\$';
var typeParams = type.typeParameters.map((p) => p.name);
if (isPublic(name)) _exports.add(genericName);
- return js.statement('const # = dart.generic(function(#) { #; return #; });',
- [genericName, typeParams, body, name]);
+
+ return js.statement('const # = #(function(#) { #; return #; });',
+ [genericName, _dartGeneric, typeParams, body, name]);
}
+ get _dartGeneric =>
+ 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!
+
+ get _dartExport =>
+ js.call('#.export', [_isDartRuntime ? _utilsLibVar : _runtimeLibVar]);
+
+ get _dartFn => js.call('#.fn', _isDartRuntime ? _rttiLibVar : _runtimeLibVar);
+
+ get _dartSetSignature => js.call(
+ '#.setSignature', [_isDartRuntime ? _classesLibVar : _runtimeLibVar]);
+
final _hasDeferredSupertype = new HashSet<ClassElement>();
bool _deferIfNeeded(DartType type, ClassElement current) {
@@ -832,7 +889,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
if (!sigFields.isEmpty || extensions.isNotEmpty) {
var sig = new JS.ObjectInitializer(sigFields);
var classExpr = new JS.Identifier(name);
- body.add(js.statement('dart.setSignature(#, #);', [classExpr, sig]));
+ body.add(js.statement('#(#, #);', [_dartSetSignature, classExpr, sig]));
}
}
@@ -1305,15 +1362,15 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
var body = <JS.Statement>[];
_flushLibraryProperties(body);
- var name = node.name.name;
+ var name = _getJsName(node.element) ?? node.name.name;
var fn = _visit(node.functionExpression);
- bool needsTagging = true;
+ // Don't tag functions defined in the low-level runtime.
+ bool needsTagging = !_isDartRuntime;
if (currentLibrary.source.isInSystemLibrary &&
_isInlineJSFunction(node.functionExpression)) {
fn = _simplifyPassThroughArrowFunCallBody(fn);
- needsTagging = !_isDartUtils;
}
var id = new JS.Identifier(name);
@@ -1345,23 +1402,17 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
bool _isJSInvocation(Expression expr) =>
expr is MethodInvocation && isInlineJS(expr.methodName.staticElement);
- // Simplify `(args) => ((x, y) => { ... })(x, y)` to `(args) => { ... }`.
- // Note: we don't check if the top-level args match the ones passed through
- // the arrow function, which allows silently passing args through to the
- // body (which only works if we don't do weird renamings of Dart params).
+ // Simplify `(args) => (() => { ... })()` to `(args) => { ... }`.
+ // 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.
+ // works if we don't do weird renamings of Dart params.
JS.Fun _simplifyPassThroughArrowFunCallBody(JS.Fun fn) {
- String getIdent(JS.Node node) => node is JS.Identifier ? node.name : null;
- List<String> getIdents(List params) =>
- params.map(getIdent).toList(growable: false);
-
if (fn.body is JS.Block && fn.body.statements.length == 1) {
var stat = fn.body.statements.single;
if (stat is JS.Return && stat.value is JS.Call) {
JS.Call call = stat.value;
- if (call.target is JS.ArrowFun) {
- var passedArgs = getIdents(call.arguments);
+ if (call.target is JS.ArrowFun && call.arguments.isEmpty) {
JS.ArrowFun innerFun = call.target;
- if (_listEquality.equals(getIdents(innerFun.params), passedArgs)) {
+ if (innerFun.params.isEmpty) {
return new JS.Fun(fn.params, innerFun.body);
}
}
@@ -1409,12 +1460,13 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
type.optionalParameterTypes.isEmpty &&
type.namedParameterTypes.isEmpty &&
type.normalParameterTypes.every((t) => t.isDynamic)) {
- return js.call('dart.fn(#)', [clos]);
+ return js.call('#(#)', [_dartFn, clos]);
}
if (lazy) {
- return js.call('dart.fn(#, () => #)', [clos, _emitFunctionRTTI(type)]);
+ return js.call(
+ '#(#, () => #)', [_dartFn, clos, _emitFunctionRTTI(type)]);
}
- return js.call('dart.fn(#, #)', [clos, _emitFunctionTypeParts(type)]);
+ return js.call('#(#, #)', [_dartFn, clos, _emitFunctionTypeParts(type)]);
}
throw 'Function has non function type: $type';
}
@@ -1569,7 +1621,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
_loader.declareBeforeUse(element);
- var name = element.name;
+ 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
// type literal
if (element is ClassElement ||
@@ -1581,7 +1633,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
// library member
if (element.enclosingElement is CompilationUnitElement) {
- return _maybeQualifiedName(element);
+ return _maybeQualifiedName(element, name);
}
// Unqualified class member. This could mean implicit-this, or implicit
@@ -1884,11 +1936,32 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
new JS.Block(_visitList(node.statements) as List<JS.Statement>,
isScope: true);
+ /// Return the type constructor `_foolib.Bar$` given `Bar` from lib `_foolib`.
+ ///
+ /// This implements / expands the `genericTypeConstructor` intrinsic defined
+ /// in `foreign_helper.dart`.
+ 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
+ var ref = _visit(typeExpression);
+ if (ref is JS.PropertyAccess) {
+ var name = (ref.selector as JS.LiteralString).valueWithoutQuotes;
+ return new JS.PropertyAccess(
+ ref.receiver, new JS.LiteralString("'$name\$'"));
+ } else if (ref is JS.MaybeQualifiedId) {
+ var name = (ref.name as JS.Identifier).name;
+ return new JS.PropertyAccess(ref.qualifier, new JS.Identifier('$name\$'));
+ } else {
+ throw new ArgumentError('Invalid type ref: $ref (${ref?.runtimeType})');
+ }
+ }
+
@override
visitMethodInvocation(MethodInvocation node) {
if (node.operator != null && node.operator.lexeme == '?.') {
return _emitNullSafe(node);
}
+ if (isGenericTypeConstructorInvocation(node)) {
+ 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
+ }
var target = _getTarget(node);
var result = _emitForeignJS(node);
@@ -2214,7 +2287,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
var isJSTopLevel = field.isFinal && _isFinalJSDecl(field);
if (isJSTopLevel) eagerInit = true;
- var fieldName = field.name.name;
+ var fieldName = _getJsName(element) ?? field.name.name;
+
if ((field.isConst && eagerInit && element is TopLevelVariableElement) ||
isJSTopLevel) {
// constant fields don't change, so we can generate them as `let`
@@ -2850,7 +2924,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
} else if (_requiresStaticDispatch(target, memberId.name)) {
var type = member.type;
var clos = js.call('dart.#.bind(#)', [name, _visit(target)]);
- return js.call('dart.fn(#, #)', [clos, _emitFunctionTypeParts(type)]);
+ return js.call(
+ '#(#, #)', [_dartFn, clos, _emitFunctionTypeParts(type)]);
}
code = 'dart.bind(#, #)';
} else if (_requiresStaticDispatch(target, memberId.name)) {
@@ -3419,8 +3494,13 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
/// declaration) as it doesn't have any meaningful rules enforced.
JS.Identifier _libraryName(LibraryElement library) {
if (library == currentLibrary) return _exportsVar;
- return _imports.putIfAbsent(
- library, () => new JS.TemporaryId(jsLibraryName(library)));
+ return _imports.putIfAbsent(library, () {
+ var name = library.name;
+ 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.
+ 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.
+ else if (name == 'dart._rtti') return _rttiLibVar;
+ else return new JS.TemporaryId(jsLibraryName(library));
+ });
}
DartType getStaticType(Expression e) => rules.getStaticType(e);
« 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