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

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

Issue 1088943006: implement tear offs (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 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 unified diff | Download patch
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; 7 import 'dart:collection' show HashSet, HashMap;
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 1011 matching lines...) Expand 10 before | Expand all | Expand 10 after
1022 (element.library != libraryInfo.library || 1022 (element.library != libraryInfo.library ||
1023 element is TopLevelVariableElement && !element.isConst)) { 1023 element is TopLevelVariableElement && !element.isConst)) {
1024 return js.call('#.#', [_libraryName(element.library), name]); 1024 return js.call('#.#', [_libraryName(element.library), name]);
1025 } 1025 }
1026 1026
1027 // Unqualified class member. This could mean implicit-this, or implicit 1027 // Unqualified class member. This could mean implicit-this, or implicit
1028 // call to a static from the same class. 1028 // call to a static from the same class.
1029 if (element is ClassMemberElement && element is! ConstructorElement) { 1029 if (element is ClassMemberElement && element is! ConstructorElement) {
1030 bool isStatic = element.isStatic; 1030 bool isStatic = element.isStatic;
1031 var type = element.enclosingElement.type; 1031 var type = element.enclosingElement.type;
1032 var member = _emitMemberName(name, isStatic: isStatic, type: type);
1032 1033
1033 // For instance methods, we add implicit-this.
1034 // For static methods, we add the raw type name, without generics or 1034 // For static methods, we add the raw type name, without generics or
1035 // library prefix. We don't need those because static calls can't use 1035 // library prefix. We don't need those because static calls can't use
1036 // the generic type. 1036 // the generic type.
1037 var target = isStatic ? new JS.Identifier(type.name) : new JS.This(); 1037 if (isStatic) {
1038 var member = _emitMemberName(name, isStatic: isStatic, type: type); 1038 return js.call('#.#', [type.name, member]);
1039 return new JS.PropertyAccess(target, member); 1039 }
1040
1041 // For instance members, we add implicit-this.
1042 // For method tear-offs, we ensure it's a bound method.
1043 var code = 'this.#';
1044 if (element is MethodElement && !inInvocationContext(node)) {
1045 code += '.bind(this)';
1046 }
1047 return js.call(code, member);
1040 } 1048 }
1041 1049
1042 // initializing formal parameter, e.g. `Point(this.x)` 1050 // initializing formal parameter, e.g. `Point(this.x)`
1043 if (element is ParameterElement && 1051 if (element is ParameterElement &&
1044 element.isInitializingFormal && 1052 element.isInitializingFormal &&
1045 element.isPrivate) { 1053 element.isPrivate) {
1046 /// Rename private names so they don't shadow the private field symbol. 1054 /// Rename private names so they don't shadow the private field symbol.
1047 /// The renamer would handle this, but it would prefer to rename the 1055 /// The renamer would handle this, but it would prefer to rename the
1048 /// temporary used for the private symbol. Instead rename the parameter. 1056 /// temporary used for the private symbol. Instead rename the parameter.
1049 return _getTemp(element, '${name.substring(1)}'); 1057 return _getTemp(element, '${name.substring(1)}');
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
1221 @override 1229 @override
1222 JS.Block visitBlock(Block node) => new JS.Block(_visitList(node.statements)); 1230 JS.Block visitBlock(Block node) => new JS.Block(_visitList(node.statements));
1223 1231
1224 @override 1232 @override
1225 visitMethodInvocation(MethodInvocation node) { 1233 visitMethodInvocation(MethodInvocation node) {
1226 var target = node.isCascaded ? _cascadeTarget : node.target; 1234 var target = node.isCascaded ? _cascadeTarget : node.target;
1227 1235
1228 var result = _emitForeignJS(node); 1236 var result = _emitForeignJS(node);
1229 if (result != null) return result; 1237 if (result != null) return result;
1230 1238
1231 // TODO(jmesserly): if we try to call a getter returning a function with
1232 // a call method, we don't generate the `.call` correctly.
1233 String code; 1239 String code;
1234 if (target == null || isLibraryPrefix(target)) { 1240 if (target == null || isLibraryPrefix(target)) {
1235 if (rules.isDynamicCall(node.methodName)) { 1241 if (rules.isDynamicCall(node.methodName)) {
1236 code = 'dart.$DCALL(#, #)'; 1242 code = 'dart.$DCALL(#, #)';
1237 } else { 1243 } else {
1238 code = '#(#)'; 1244 code = '#(#)';
1239 } 1245 }
1240 return js.call( 1246 return js.call(
1241 code, [_visit(node.methodName), _visit(node.argumentList)]); 1247 code, [_visit(node.methodName), _visit(node.argumentList)]);
1242 } 1248 }
1243 1249
1244 // TODO(jmesserly): if the methodName resolves statically but the call is 1250 if (rules.isDynamicTarget(target)) {
1245 // dynamic (e.g. `obj.method` is resolved to a field of type `Function`), we
1246 // could generate call(#.#, #). Not sure if that's worth it.
1247 if (rules.isDynamicCall(node.methodName)) {
1248 code = 'dart.$DSEND(#, #, #)'; 1251 code = 'dart.$DSEND(#, #, #)';
1252 } else if (rules.isDynamicCall(node.methodName)) {
1253 // This is a dynamic call to a statically know target. For example:
1254 // class Foo { Function bar; }
1255 // new Foo().bar(); // dynamic call
1256 code = 'dart.$DCALL(#.#, #)';
1249 } else { 1257 } else {
1250 code = '#.#(#)'; 1258 code = '#.#(#)';
1251 } 1259 }
1252 return js.call(code, [ 1260 return js.call(code, [
1253 _visit(target), 1261 _visit(target),
1254 _emitMemberName(node.methodName.name, type: getStaticType(target)), 1262 _emitMemberName(node.methodName.name, type: getStaticType(target)),
1255 _visit(node.argumentList) 1263 _visit(node.argumentList)
1256 ]); 1264 ]);
1257 } 1265 }
1258 1266
(...skipping 530 matching lines...) Expand 10 before | Expand all | Expand 10 after
1789 JS.This visitThisExpression(ThisExpression node) => new JS.This(); 1797 JS.This visitThisExpression(ThisExpression node) => new JS.This();
1790 1798
1791 @override 1799 @override
1792 JS.Super visitSuperExpression(SuperExpression node) => new JS.Super(); 1800 JS.Super visitSuperExpression(SuperExpression node) => new JS.Super();
1793 1801
1794 @override 1802 @override
1795 visitPrefixedIdentifier(PrefixedIdentifier node) { 1803 visitPrefixedIdentifier(PrefixedIdentifier node) {
1796 if (isLibraryPrefix(node.prefix)) { 1804 if (isLibraryPrefix(node.prefix)) {
1797 return _visit(node.identifier); 1805 return _visit(node.identifier);
1798 } else { 1806 } else {
1799 return _emitGet(node.prefix, node.identifier.name); 1807 return _emitGet(node.prefix, node.identifier);
1800 } 1808 }
1801 } 1809 }
1802 1810
1803 @override 1811 @override
1804 visitPropertyAccess(PropertyAccess node) => 1812 visitPropertyAccess(PropertyAccess node) =>
1805 _emitGet(_getTarget(node), node.propertyName.name); 1813 _emitGet(_getTarget(node), node.propertyName);
1806 1814
1807 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. 1815 /// Shared code for [PrefixedIdentifier] and [PropertyAccess].
1808 JS.Expression _emitGet(Expression target, String memberName) { 1816 JS.Expression _emitGet(Expression target, SimpleIdentifier memberId) {
1809 var name = _emitMemberName(memberName, type: getStaticType(target)); 1817 var name = _emitMemberName(memberId.name, type: getStaticType(target));
1810 if (rules.isDynamicTarget(target)) { 1818 if (rules.isDynamicTarget(target)) {
1811 return js.call('dart.$DLOAD(#, #)', [_visit(target), name]); 1819 return js.call('dart.$DLOAD(#, #)', [_visit(target), name]);
1820 }
1821
1822 String code;
1823 var member = memberId.staticElement;
1824 if (member != null && member is MethodElement) {
1825 // Tear-off methods: explicitly bind it.
1826 if (isStateless(target, target)) {
1827 return js.call('#.#.bind(#)', [_visit(target), name, _visit(target)]);
1828 }
1829 code = 'dart.bind(#, #)';
1812 } else { 1830 } else {
1813 return js.call('#.#', [_visit(target), name]); 1831 code = '#.#';
1814 } 1832 }
1833
1834 return js.call(code, [_visit(target), name]);
1815 } 1835 }
1816 1836
1837 /// Emits a generic send, like an operator method.
1838 ///
1839 /// **Please note** this function does not support method invocation syntax
1840 /// `obj.name(args)` because that could be a getter followed by a call.
1841 /// See [visitMethodInvocation].
1817 JS.Expression _emitSend( 1842 JS.Expression _emitSend(
1818 Expression target, String name, List<Expression> args) { 1843 Expression target, String name, List<Expression> args) {
1819 var type = getStaticType(target); 1844 var type = getStaticType(target);
1820 var memberName = _emitMemberName(name, unary: args.isEmpty, type: type); 1845 var memberName = _emitMemberName(name, unary: args.isEmpty, type: type);
1821 if (rules.isDynamicTarget(target)) { 1846 if (rules.isDynamicTarget(target)) {
1822 // dynamic dispatch 1847 // dynamic dispatch
1823 var dynamicHelper = const {'[]': DINDEX, '[]=': DSETINDEX}[name]; 1848 var dynamicHelper = const {'[]': DINDEX, '[]=': DSETINDEX}[name];
1824 if (dynamicHelper != null) { 1849 if (dynamicHelper != null) {
1825 return js.call( 1850 return js.call(
1826 'dart.$dynamicHelper(#, #)', [_visit(target), _visitList(args)]); 1851 'dart.$dynamicHelper(#, #)', [_visit(target), _visitList(args)]);
1827 } 1852 }
1828 return js.call('dart.$DSEND(#, #, #)', [ 1853 return js.call('dart.$DSEND(#, #, #)', [
1829 _visit(target), 1854 _visit(target),
1830 memberName, 1855 memberName,
1831 _visitList(args) 1856 _visitList(args)
1832 ]); 1857 ]);
1833 } 1858 }
1859
1834 if (_isJSBuiltinType(type)) { 1860 if (_isJSBuiltinType(type)) {
1835 // static call pattern for bultins. 1861 // static call pattern for builtins.
1836 return js.call('#.#(#, #)', [ 1862 return js.call('#.#(#, #)', [
1837 _emitTypeName(type), 1863 _emitTypeName(type),
1838 memberName, 1864 memberName,
1839 _visit(target), 1865 _visit(target),
1840 _visitList(args) 1866 _visitList(args)
1841 ]); 1867 ]);
1842 } 1868 }
1843 // Generic dispatch to a statically known method. 1869 // Generic dispatch to a statically known method.
1844 return js.call('#.#(#)', [_visit(target), memberName, _visitList(args)]); 1870 return js.call('#.#(#)', [_visit(target), memberName, _visitList(args)]);
1845 } 1871 }
(...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after
2384 return filepath; 2410 return filepath;
2385 } 2411 }
2386 2412
2387 // TODO(jmesserly): validate the library. See issue #135. 2413 // TODO(jmesserly): validate the library. See issue #135.
2388 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName'; 2414 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName';
2389 2415
2390 // TODO(jacobr): we would like to do something like the following 2416 // TODO(jacobr): we would like to do something like the following
2391 // but we don't have summary support yet. 2417 // but we don't have summary support yet.
2392 // bool _supportJsExtensionMethod(AnnotatedNode node) => 2418 // bool _supportJsExtensionMethod(AnnotatedNode node) =>
2393 // _getAnnotation(node, "SupportJsExtensionMethod") != null; 2419 // _getAnnotation(node, "SupportJsExtensionMethod") != null;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698