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

Unified Diff: lib/src/compiler/code_generator.dart

Issue 1918033002: Remove virtualField helper, just emit getters/setters in codegen. (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 4 years, 8 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
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | test/codegen/expect/fieldtest.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/src/compiler/code_generator.dart
diff --git a/lib/src/compiler/code_generator.dart b/lib/src/compiler/code_generator.dart
index 2c19b39ef6f2c7ac0a9af6e10978145d953ec503..4aab66c4c08c5621a08003d4c404ebeec3689d2e 100644
--- a/lib/src/compiler/code_generator.dart
+++ b/lib/src/compiler/code_generator.dart
@@ -81,6 +81,8 @@ class CodeGenerator extends GeneralizingAstVisitor
final _privateNames =
new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>();
+ final _virtualFields = new HashMap<VariableDeclaration, JS.TemporaryId>();
Jennifer Messerly 2016/04/25 22:47:04 Generally we don't use AST nodes as hash keys. Sho
Harry Terkelsen 2016/04/26 18:29:27 Done.
+ final _virtualFieldSymbols = new HashMap<ClassElement, List<JS.Statement>>();
Jennifer Messerly 2016/04/25 22:47:04 do we need this map? could we simply keep a List<J
Harry Terkelsen 2016/04/26 18:29:27 Done.
final _initializingFormalTemps =
new HashMap<ParameterElement, JS.TemporaryId>();
@@ -531,9 +533,16 @@ class CodeGenerator extends GeneralizingAstVisitor
}
}
+ JS.Expression className;
+ if (classElem.typeParameters.isNotEmpty) {
+ className = new JS.Identifier(classElem.name);
Jennifer Messerly 2016/04/25 22:47:04 there was a comment below: "// Generic classes wil
Harry Terkelsen 2016/04/26 18:29:27 Done.
+ } else {
+ className = _emitTopLevelName(classElem);
+ }
+
var allFields = new List.from(fields)..addAll(staticFields);
var classExpr = _emitClassExpression(
- classElem, _emitClassMethods(node, ctors, fields),
+ classElem, _emitClassMethods(node, ctors, fields, className, classElem),
fields: allFields);
var body = <JS.Statement>[];
@@ -541,12 +550,12 @@ class CodeGenerator extends GeneralizingAstVisitor
_initExtensionSymbols(classElem, methods, fields, body);
// Emit the class, e.g. `core.Object = class Object { ... }`
- JS.Expression className = _defineClass(classElem, classExpr, body);
+ _defineClass(classElem, className, classExpr, body);
// Emit things that come after the ES6 `class ... { ... }`.
_setBaseClass(classElem, className, body);
_defineNamedConstructors(ctors, body, className);
- _emitVirtualFields(classElem, fields, className, body);
+ _emitVirtualFieldSymbols(classElem, body);
_emitClassSignature(methods, classElem, ctors, extensions, className, body);
_defineExtensionMembers(extensions, className, body);
_emitClassMetadata(node.metadata, className, body);
@@ -563,19 +572,20 @@ class CodeGenerator extends GeneralizingAstVisitor
return _statement(body);
}
- JS.Expression _defineClass(ClassElement classElem,
+ void _defineClass(ClassElement classElem, JS.Expression className,
JS.ClassExpression classExpr, List<JS.Statement> body) {
- JS.Expression className;
if (classElem.typeParameters.isNotEmpty) {
// Generic classes will be defined inside a function that closes over the
// type parameter. So we can use their local variable name directly.
- className = classExpr.name;
body.add(new JS.ClassDeclaration(classExpr));
} else {
- className = _emitTopLevelName(classElem);
body.add(js.statement('# = #;', [className, classExpr]));
}
- return className;
+ }
+
+ void _emitVirtualFieldSymbols(ClassElement elem, List<JS.Statement> body) {
+ if (_virtualFieldSymbols[elem] == null) return;
+ body.addAll(_virtualFieldSymbols[elem]);
}
List<JS.Identifier> _emitTypeFormals(List<TypeParameterElement> typeFormals) {
@@ -752,8 +762,12 @@ class CodeGenerator extends GeneralizingAstVisitor
return jsMethods;
}
- List<JS.Method> _emitClassMethods(ClassDeclaration node,
- List<ConstructorDeclaration> ctors, List<FieldDeclaration> fields) {
+ List<JS.Method> _emitClassMethods(
+ ClassDeclaration node,
+ List<ConstructorDeclaration> ctors,
+ List<FieldDeclaration> fields,
+ JS.Expression className,
+ ClassElement classElem) {
Jennifer Messerly 2016/04/25 22:47:04 This parameter isn't needed. See the very next li
Harry Terkelsen 2016/04/26 18:29:27 Done.
var element = node.element;
var type = element.type;
var isObject = type.isObject;
@@ -783,8 +797,21 @@ class CodeGenerator extends GeneralizingAstVisitor
hasIterator = true;
jsMethods.add(_emitIterable(type));
}
- } else if (m is FieldDeclaration && _extensionTypes.contains(element)) {
- jsMethods.addAll(_emitNativeFieldAccessors(m));
+ } else if (m is FieldDeclaration) {
+ if (_extensionTypes.contains(element)) {
+ jsMethods.addAll(_emitNativeFieldAccessors(m));
+ continue;
+ }
+ if (m.isStatic) continue;
+ for (VariableDeclaration field in m.fields.variables) {
+ var propertyOverrideResult = checkForPropertyOverride(
+ field.element, superclasses, _extensionTypes);
+ if (propertyOverrideResult.foundGetter ||
Jennifer Messerly 2016/04/25 22:47:04 consider: a shorter name here. "overrideInfo" or
Harry Terkelsen 2016/04/26 18:29:27 Done.
+ propertyOverrideResult.foundSetter) {
+ jsMethods.addAll(
+ _emitVirtualFieldAccessor(field, type, className, classElem));
Jennifer Messerly 2016/04/25 22:47:04 fyi -- you probably don't need to pass classElem o
Harry Terkelsen 2016/04/26 18:29:27 Done.
+ }
+ }
}
}
@@ -803,6 +830,46 @@ class CodeGenerator extends GeneralizingAstVisitor
return jsMethods.where((m) => m != null).toList(growable: false);
}
+ /// This is called whenever a derived class needs to introduce a new field,
+ /// shadowing a field or getter/setter pair on its parent.
+ ///
+ /// This is important because otherwise, trying to read or write the field
+ /// would end up calling the getter or setter, and one of those might not even
+ /// exist, resulting in a runtime error. Even if they did exist, that's the
+ /// wrong behavior if a new field was declared.
+ List<JS.Method> _emitVirtualFieldAccessor(VariableDeclaration field,
+ InterfaceType type, JS.Expression className, ClassElement classElem) {
+ var virtualField = _emitVirtualFieldSymbol(field, className, classElem);
+ var result = <JS.Method>[];
+ var name = _emitMemberName(field.element.name, type: type);
+ var getter = js.call('function() { return this[#]; }', [virtualField]);
+ result.add(new JS.Method(name, getter, isGetter: true));
+
+ if (field.isFinal) {
+ var setter = js.call(
+ 'function(value) {'
Jennifer Messerly 2016/04/25 22:47:04 style comment: triple quote style is nicer for the
Harry Terkelsen 2016/04/26 18:29:27 Done.
+ ' var f = this[#];'
+ ' if (f === undefined) {'
Jennifer Messerly 2016/04/25 22:47:04 Hmmmm, I'm a little confused about what's going on
Harry Terkelsen 2016/04/26 18:29:27 Done.
+ ' this[#] = value;'
+ ' } else {'
+ ' super[#] = value;'
+ ' }'
+ '}',
+ [virtualField, virtualField, name]);
+ result.add(new JS.Method(name, setter, isSetter: true));
+ } else {
+ var setter =
+ js.call('function(value) { this[#] = value; }', [virtualField]);
+ result.add(new JS.Method(name, setter, isSetter: true));
+ }
+
+ return result;
+ }
+
+ /// Emit a getter or setter that simply forwards to the superclass getter or
+ /// setter. This is needed because in ES6, if you only override a getter
+ /// (alternatively, a setter), then there is an implicit override of the
+ /// setter (alternatively, the getter) that does nothing.
JS.Method _emitSuperAccessorWrapper(MethodDeclaration method,
InterfaceType type, List<ClassElement> superclasses) {
var methodElement = method.element as PropertyAccessorElement;
@@ -911,26 +978,6 @@ class CodeGenerator extends GeneralizingAstVisitor
}
}
- /// Emits instance fields, if they are virtual
- /// (in other words, they override a getter/setter pair).
- void _emitVirtualFields(
- ClassElement classElement,
- List<FieldDeclaration> fields,
- JS.Expression className,
- List<JS.Statement> body) {
- List<ClassElement> superclasses = getSuperclasses(classElement);
- for (FieldDeclaration member in fields) {
- for (VariableDeclaration field in member.fields.variables) {
- var propertyOverrideResult = checkForPropertyOverride(
- field.element, superclasses, _extensionTypes);
- if (propertyOverrideResult.foundGetter ||
- propertyOverrideResult.foundSetter) {
- body.add(_overrideField(className, field.element));
- }
- }
- }
- }
-
void _defineNamedConstructors(List<ConstructorDeclaration> ctors,
List<JS.Statement> body, JS.Expression className) {
for (ConstructorDeclaration member in ctors) {
@@ -1137,12 +1184,6 @@ class CodeGenerator extends GeneralizingAstVisitor
_collectExtensions(type.superclass, types);
}
- JS.Statement _overrideField(JS.Expression className, FieldElement e) {
- var cls = e.enclosingElement;
- return js.statement('dart.virtualField(#, #)',
- [className, _emitMemberName(e.name, type: cls.type)]);
- }
-
/// Generates the implicit default constructor for class C of the form
/// `C() : super() {}`.
JS.Method _emitImplicitConstructor(
@@ -3673,6 +3714,19 @@ class CodeGenerator extends GeneralizingAstVisitor
});
}
+ JS.TemporaryId _emitVirtualFieldSymbol(VariableDeclaration field,
+ JS.Expression className, ClassElement classElem) {
+ return _virtualFields.putIfAbsent(field, () {
+ var fieldName = _emitMemberName(field.element.name,
+ type: (field.element.enclosingElement as ClassElement).type);
+ var id = new JS.TemporaryId(field.name.name);
+ _virtualFieldSymbols.putIfAbsent(classElem, () => <JS.Statement>[]).add(js
+ .statement('const # = Symbol(#.name + "." + #.toString());',
+ [id, className, fieldName]));
+ return id;
+ });
+ }
+
bool _externalOrNative(node) =>
node.externalKeyword != null || _functionBody(node) is NativeFunctionBody;
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | test/codegen/expect/fieldtest.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698