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

Unified Diff: lib/src/codegen/js_codegen.dart

Issue 1011153002: js: fix core.Object, output order, static const fields (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 9 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 side-by-side diff with in-line comments
Download patch
Index: lib/src/codegen/js_codegen.dart
diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart
index 6f135f0d21cad9d566835518470bb9e35b167124..ac166b70a8b13a97d6fbf856229060fa95904d24 100644
--- a/lib/src/codegen/js_codegen.dart
+++ b/lib/src/codegen/js_codegen.dart
@@ -38,6 +38,12 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
final LibraryInfo libraryInfo;
final TypeRules rules;
+ // TODO(jmesserly): this is needed because RestrictedTypeRules can send
+ // messages to CheckerReporter, for things like missing types.
+ // We should probably refactor so this can't happen, as codegen would be too
+ // late to be issuing these messages.
+ final CheckerReporter _checkerReporter;
+
/// The variable for the target of the current `..` cascade expression.
SimpleIdentifier _cascadeTarget;
/// The variable for the current catch clause
@@ -52,26 +58,22 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
final _privateNames = new HashSet<String>();
final _pendingPrivateNames = <String>[];
- JSCodegenVisitor(LibraryInfo libraryInfo, TypeRules rules)
- : libraryInfo = libraryInfo,
- rules = rules;
+ JSCodegenVisitor(this.libraryInfo, this.rules, this._checkerReporter);
Element get currentLibrary => libraryInfo.library;
- JS.Program generateLibrary(
- Iterable<CompilationUnit> units, CheckerReporter reporter) {
+ JS.Program emitLibrary(LibraryUnit library) {
var body = <JS.Statement>[];
- for (var unit in units) {
- // TODO(jmesserly): this is needed because RestrictedTypeRules can send
- // messages to CheckerReporter, for things like missing types.
- // We should probably refactor so this can't happen.
- var source = unit.element.source;
- _constEvaluator = new ConstantEvaluator(source, rules.provider);
- reporter.enterSource(source);
+
+ // Visit parts first, since the "part" declarations come before code
+ // in the main library's compilation unit.
+ for (var unit in library.parts) {
body.add(_visit(unit));
- reporter.leaveSource();
}
+ // Visit main library
+ body.add(_visit(library.library));
+
if (_exports.isNotEmpty) body.add(js.comment('Exports:'));
// TODO(jmesserly): make these immutable in JS?
@@ -92,6 +94,11 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
@override
JS.Statement visitCompilationUnit(CompilationUnit node) {
+ var source = node.element.source;
+
+ _constEvaluator = new ConstantEvaluator(source, rules.provider);
+ _checkerReporter.enterSource(source);
+
// TODO(jmesserly): scriptTag, directives.
var body = <JS.Statement>[];
for (var child in node.declarations) {
@@ -114,6 +121,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
_flushLazyFields(body);
_flushLibraryProperties(body);
+ _checkerReporter.leaveSource();
+
assert(_pendingPrivateNames.isEmpty);
return _statement(body);
}
@@ -219,7 +228,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
// TODO(jmesserly): we may not want this to be `dynamic` if the generic
// has a lower bound, e.g. `<T extends SomeType>`.
// https://github.com/dart-lang/dart-dev-compiler/issues/38
- var typeArgs = new List.filled(node.typeParameters.length, 'dynamic');
+ var typeArgs =
+ new List.filled(node.typeParameters.length, js.call('dart.dynamic'));
var dynInst = js.statement('let # = #(#);', [name, genericName, typeArgs]);
@@ -233,6 +243,9 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
JS.Statement visitClassDeclaration(ClassDeclaration node) {
currentClass = node;
+ // dart:core Object is a bit special.
+ var isObject = node.element.type.isObject;
+
var body = <JS.Statement>[];
var name = node.name.name;
@@ -250,13 +263,13 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
var jsMethods = <JS.Method>[];
// Iff no constructor is specified for a class C, it implicitly has a
// default constructor `C() : super() {}`, unless C is class Object.
- if (ctors.isEmpty && !node.element.type.isObject) {
+ if (ctors.isEmpty && !isObject) {
jsMethods.add(_emitImplicitConstructor(node, name, fields));
}
for (var member in node.members) {
if (member is ConstructorDeclaration) {
- jsMethods.add(_emitConstructor(member, name, fields));
+ jsMethods.add(_emitConstructor(member, name, fields, isObject));
} else if (member is MethodDeclaration) {
jsMethods.add(_visit(member));
}
@@ -278,11 +291,11 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
jsMethods.add(new JS.Method(js.call('Symbol.iterator'), body));
}
- JS.Expression heritage;
+ JS.Expression heritage = null;
if (node.extendsClause != null) {
heritage = _visit(node.extendsClause.superclass);
- } else {
- heritage = js.call('dart.Object');
+ } else if (!isObject) {
+ heritage = _emitTypeName(rules.provider.objectType);
}
if (node.withClause != null) {
var mixins = _visitList(node.withClause.mixinTypes);
@@ -341,16 +354,44 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
}
JS.Method _emitConstructor(ConstructorDeclaration node, String className,
- List<FieldDeclaration> fields) {
+ List<FieldDeclaration> fields, bool isObject) {
if (_externalOrNative(node)) return null;
var name = _constructorName(className, node.name);
+ // Code generation for Object's constructor.
+ JS.Block body;
+ if (isObject &&
+ node.body is EmptyFunctionBody &&
+ node.constKeyword != null &&
+ node.name == null) {
+ // Implements Dart constructor behavior. Because of V8 `super`
+ // [constructor restrictions]
+ // (https://code.google.com/p/v8/issues/detail?id=3330#c65)
+ // we cannot currently emit actual ES6 constructors with super calls.
+ // Instead we use the same trick as named constructors, and do them as
+ // instance methods that perform initialization.
+ // TODO(jmesserly): we'll need to rethink this once the ES6 spec and V8
+ // settles. See <https://github.com/dart-lang/dev_compiler/issues/51>.
+ // Performance of this pattern is likely to be bad.
+ body = js.statement('''{
+ // Get the class name for this instance.
+ var name = this.constructor.name;
+ // Call the default constructor.
+ var init = this[name];
+ var result = void 0;
+ if (init) result = init.apply(this, arguments);
+ return result === void 0 ? this : result;
+ }''');
+ } else {
+ body = _emitConstructorBody(node, fields);
+ }
+
// We generate constructors as initializer methods in the class;
// this allows use of `super` for instance methods/properties.
// It also avoids V8 restrictions on `super` in default constructors.
- return new JS.Method(new JS.PropertyName(name),
- new JS.Fun(_visit(node.parameters), _emitConstructorBody(node, fields)))
+ return new JS.Method(
+ new JS.PropertyName(name), new JS.Fun(_visit(node.parameters), body))
..sourceInformation = node;
}
@@ -654,12 +695,19 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
return js.commentExpression(
'Unimplemented unknown name', new JS.VariableUse(node.name));
}
+
var name = node.name;
+ var variable = e is PropertyAccessorElement ? e.variable : e;
+
if (e.enclosingElement is CompilationUnitElement &&
- (e.library != libraryInfo.library || _needsModuleGetter(e))) {
+ (e.library != libraryInfo.library ||
+ variable is TopLevelVariableElement && !variable.isConst)) {
return js.call('#.#', [_libraryName(e.library), name]);
} else if (currentClass != null && _needsImplicitThis(e)) {
return js.call('this.#', _jsMemberName(name));
+ } else if (variable is ConstFieldElementImpl) {
+ var className = (variable.enclosingElement as ClassElement).name;
+ return js.call('#.#', [className, name]);
} else if (e is ParameterElement && e.isInitializingFormal) {
name = _fieldParameterName(name);
}
@@ -1718,15 +1766,6 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
return _constEvaluator.evaluate(initializer);
}
- /// Returns true if [element] is a getter in JS, therefore needs
- /// `lib.topLevel` syntax instead of just `topLevel`.
- bool _needsModuleGetter(Element element) {
- if (element is PropertyAccessorElement) {
- element = (element as PropertyAccessorElement).variable;
- }
- return element is TopLevelVariableElement && !element.isConst;
- }
-
_visit(AstNode node) {
if (node == null) return null;
var result = node.accept(this);
@@ -1925,10 +1964,9 @@ class JSGenerator extends CodeGenerator {
JSGenerator(String outDir, Uri root, TypeRules rules, this.options)
: super(outDir, root, rules);
- String generateLibrary(Iterable<CompilationUnit> units, LibraryInfo info,
- CheckerReporter reporter) {
- JS.Program jsTree =
- new JSCodegenVisitor(info, rules).generateLibrary(units, reporter);
+ String generateLibrary(
+ LibraryUnit unit, LibraryInfo info, CheckerReporter reporter) {
+ var jsTree = new JSCodegenVisitor(info, rules, reporter).emitLibrary(unit);
var outputPath = path.join(outDir, jsOutputPath(info, root));
new Directory(path.dirname(outputPath)).createSync(recursive: true);
« no previous file with comments | « lib/src/codegen/dart_codegen.dart ('k') | lib/src/info.dart » ('j') | lib/src/info.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698