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

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

Issue 1962823002: fix #552, Object members on native types (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | lib/src/compiler/nullable_type_inference.dart » ('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 134907c8e4f6cf74d67e02455d7430e00961a8ed..95dba1cdabaa92703a3e0c6a11ea8fa81638d0fa 100644
--- a/lib/src/compiler/code_generator.dart
+++ b/lib/src/compiler/code_generator.dart
@@ -224,12 +224,21 @@ class CodeGenerator extends GeneralizingAstVisitor
// Collect all Element -> Node mappings, in case we need to forward declare
// any nodes.
var nodes = new HashMap<Element, AstNode>.identity();
- compilationUnits.map(_collectElements).forEach(nodes.addAll);
+ var sdkBootstrappingFns = new List<FunctionElement>();
+ for (var unit in compilationUnits) {
+ if (_isDartRuntime(unit.element.library)) {
+ sdkBootstrappingFns.addAll(unit.element.functions);
+ }
+ _collectElements(unit, nodes);
+ }
_loader = new ElementLoader(_emitModuleItem, nodes);
// Add implicit dart:core dependency so it is first.
emitLibraryName(dartCoreLibrary);
+ // Emit SDK bootstrapping functions first, if any.
+ sdkBootstrappingFns.forEach(_loader.emitDeclaration);
+
// Visit each compilation unit and emit its code.
//
// NOTE: declarations are not necessarily emitted in this order.
@@ -319,8 +328,8 @@ class CodeGenerator extends GeneralizingAstVisitor
/// Collect toplevel elements and nodes we need to emit, and returns
/// an ordered map of these.
- static Map<Element, AstNode> _collectElements(CompilationUnit unit) {
- var map = <Element, AstNode>{};
+ static void _collectElements(
+ CompilationUnit unit, Map<Element, AstNode> map) {
for (var declaration in unit.declarations) {
if (declaration is TopLevelVariableDeclaration) {
for (var field in declaration.variables.variables) {
@@ -330,7 +339,6 @@ class CodeGenerator extends GeneralizingAstVisitor
map[declaration.element] = declaration;
}
}
- return map;
}
void _emitModuleItem(AstNode node) {
@@ -961,7 +969,7 @@ class CodeGenerator extends GeneralizingAstVisitor
// Generate a corresponding virtual getter / setter.
var name = _elementMemberName(methodElement,
- allowExtensions: _extensionTypes.isNativeClass(type.element));
+ useExtension: _extensionTypes.isNativeClass(type.element));
if (method.isGetter) {
// Generate a setter
if (field.setter != null || !propertyOverrideResult.foundSetter)
@@ -1116,7 +1124,7 @@ class CodeGenerator extends GeneralizingAstVisitor
if (extensions.isNotEmpty) {
var methodNames = <JS.Expression>[];
for (var e in extensions) {
- methodNames.add(_elementMemberName(e, allowExtensions: false));
+ methodNames.add(_elementMemberName(e, useExtension: false));
}
body.add(js.statement('dart.defineExtensionMembers(#, #);', [
className,
@@ -1154,7 +1162,7 @@ class CodeGenerator extends GeneralizingAstVisitor
continue;
}
var memberName = _elementMemberName(element,
- allowExtensions: _extensionTypes.isNativeClass(classElem));
+ useExtension: _extensionTypes.isNativeClass(classElem));
var parts = _emitFunctionTypeParts(element.type);
var property =
new JS.Property(memberName, new JS.ArrayInitializer(parts));
@@ -1210,7 +1218,7 @@ class CodeGenerator extends GeneralizingAstVisitor
var dartxNames = <JS.Expression>[];
for (var m in methods) {
if (!m.isAbstract && !m.isStatic && m.element.isPublic) {
- dartxNames.add(_elementMemberName(m.element, allowExtensions: false));
+ dartxNames.add(_elementMemberName(m.element, useExtension: false));
}
}
for (var f in fields) {
@@ -1218,7 +1226,7 @@ class CodeGenerator extends GeneralizingAstVisitor
for (var d in f.fields.variables) {
if (d.element.isPublic) {
dartxNames.add(
- _elementMemberName(d.element.getter, allowExtensions: false));
+ _elementMemberName(d.element.getter, useExtension: false));
}
}
}
@@ -1243,7 +1251,7 @@ class CodeGenerator extends GeneralizingAstVisitor
var extensionMembers = new HashSet<String>();
for (var t in types) {
for (var m in [t.methods, t.accessors].expand((e) => e)) {
- if (!m.isStatic) extensionMembers.add(m.name);
+ if (!m.isStatic && m.isPublic) extensionMembers.add(m.name);
}
}
@@ -1677,7 +1685,7 @@ class CodeGenerator extends GeneralizingAstVisitor
return annotate(
new JS.Method(
_elementMemberName(node.element,
- allowExtensions: _extensionTypes.isNativeClass(type.element)),
+ useExtension: _extensionTypes.isNativeClass(type.element)),
fn,
isGetter: node.isGetter,
isSetter: node.isSetter,
@@ -2492,9 +2500,8 @@ class CodeGenerator extends GeneralizingAstVisitor
}
}
if (_isObjectMemberCall(target, name)) {
- // Object methods require a helper for null checks & native types.
assert(typeArgs == null); // Object methods don't take type args.
- return js.call('dart.#(#, #)', [memberName, jsTarget, args]);
+ return js.call('dart.#(#, #)', [name, jsTarget, args]);
}
jsTarget = new JS.PropertyAccess(jsTarget, memberName);
@@ -2845,11 +2852,6 @@ class CodeGenerator extends GeneralizingAstVisitor
return new JS.VariableInitialization(name, _visitInitializer(node));
}
- bool _isFinalJSDecl(AstNode field) =>
- field is VariableDeclaration &&
- field.isFinal &&
- _isJSInvocation(field.initializer);
-
/// Try to emit a constant static field.
///
/// If the field's initializer does not cause side effects, and if all of
@@ -2915,10 +2917,9 @@ class CodeGenerator extends GeneralizingAstVisitor
eagerInit = false;
}
- // Treat `final x = JS('', '...')` as a const (non-lazy) to help compile
- // runtime helpers.
- // TODO(jmesserly): we don't track dependencies correctly for these.
- var isJSTopLevel = field.isFinal && _isFinalJSDecl(field);
+ // Treat dart:runtime stuff as safe to eagerly evaluate.
+ // TODO(jmesserly): it'd be nice to avoid this special case.
+ var isJSTopLevel = field.isFinal && _isDartRuntime(element.library);
if (eagerInit || isJSTopLevel) {
// Remember that we emitted it this way, so re-export can take advantage
// of this fact.
@@ -3611,8 +3612,7 @@ class CodeGenerator extends GeneralizingAstVisitor
/// For example `null.toString()` is legal in Dart, so we need to generate
/// that as `dart.toString(obj)`.
bool _isObjectMemberCall(Expression target, String memberName) {
- // Is this a member on `Object`?
- if (!isObjectProperty(memberName)) {
+ if (!isObjectMember(memberName)) {
return false;
}
@@ -3690,12 +3690,13 @@ class CodeGenerator extends GeneralizingAstVisitor
if (isSuper) {
result = js.call('dart.bind(this, #, #.#)', [name, jsTarget, name]);
} else if (_isObjectMemberCall(target, memberName)) {
- result = js.call('dart.bind(#, #, dart.#)', [jsTarget, name, name]);
+ result = js.call('dart.bind(#, #, dart.#)',
+ [jsTarget, _propertyName(memberName), memberName]);
} else {
result = js.call('dart.bind(#, #)', [jsTarget, name]);
}
} else if (_isObjectMemberCall(target, memberName)) {
- result = js.call('dart.#(#)', [name, jsTarget]);
+ result = js.call('dart.#(#)', [memberName, jsTarget]);
} else {
result = js.call('#.#', [jsTarget, name]);
}
@@ -4161,8 +4162,7 @@ class CodeGenerator extends GeneralizingAstVisitor
///
/// Unlike call sites, we always have an element available, so we can use it
/// directly rather than computing the relevant options for [_emitMemberName].
- JS.Expression _elementMemberName(ExecutableElement e,
- {bool allowExtensions: true}) {
+ JS.Expression _elementMemberName(ExecutableElement e, {bool useExtension}) {
String name;
if (e is PropertyAccessorElement) {
name = e.variable.name;
@@ -4173,7 +4173,7 @@ class CodeGenerator extends GeneralizingAstVisitor
type: (e.enclosingElement as ClassElement).type,
unary: e.parameters.isEmpty,
isStatic: e.isStatic,
- allowExtensions: allowExtensions);
+ useExtension: useExtension);
}
/// This handles member renaming for private names and operators.
@@ -4221,7 +4221,7 @@ class CodeGenerator extends GeneralizingAstVisitor
{DartType type,
bool unary: false,
bool isStatic: false,
- bool allowExtensions: true}) {
+ bool useExtension}) {
// Static members skip the rename steps.
if (isStatic) return _propertyName(name);
@@ -4241,19 +4241,20 @@ class CodeGenerator extends GeneralizingAstVisitor
name = '+$name';
}
- // Dart "extension" methods. Used for JS Array, Boolean, Number, String.
- var baseType = type;
- while (baseType is TypeParameterType) {
- baseType = baseType.element.bound;
- }
- if (allowExtensions &&
- baseType != null &&
- _extensionTypes.hasNativeSubtype(baseType) &&
- !isObjectProperty(name)) {
- return js.call('dartx.#', _propertyName(name));
+ var result = _propertyName(name);
+
+ if (useExtension == null) {
+ // Dart "extension" methods. Used for JS Array, Boolean, Number, String.
+ var baseType = type;
+ while (baseType is TypeParameterType) {
+ baseType = baseType.element.bound;
+ }
+ useExtension = baseType != null &&
+ _extensionTypes.hasNativeSubtype(baseType) &&
+ !isObjectMember(name);
}
- return _propertyName(name);
+ return useExtension ? js.call('dartx.#', result) : result;
}
JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) {
@@ -4299,18 +4300,22 @@ class CodeGenerator extends GeneralizingAstVisitor
/// a subtype of int and double (and num). It's in our "dart:_interceptors".
bool _isNumberInJS(DartType t) => rules.isSubtypeOf(t, types.numType);
- bool _isObjectGetter(String name) {
- PropertyAccessorElement element = types.objectType.element.getGetter(name);
- return (element != null && !element.isStatic);
- }
-
- bool _isObjectMethod(String name) {
- MethodElement element = types.objectType.element.getMethod(name);
- return (element != null && !element.isStatic);
- }
-
- bool isObjectProperty(String name) {
- return _isObjectGetter(name) || _isObjectMethod(name);
+ /// Return true if this is one of the methods/properties on all Dart Objects
+ /// (toString, hashCode, noSuchMethod, runtimeType).
+ ///
+ /// Operator == is excluded, as it is handled as part of the equality binary
+ /// operator.
+ bool isObjectMember(String name) {
+ // We could look these up on Object, but we have hard coded runtime helpers
+ // so it's not really providing any benefit.
+ switch (name) {
+ case 'hashCode':
+ case 'toString':
+ case 'noSuchMethod':
+ case 'runtimeType':
+ return true;
+ }
+ return false;
}
// TODO(leafp): Various analyzer pieces computed similar things.
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | lib/src/compiler/nullable_type_inference.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698