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

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

Issue 1680263002: Support for dart:typed_data (Closed) Base URL: https://github.com/dart-lang/dev_compiler.git@master
Patch Set: Address comments, rebase Created 4 years, 10 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
« no previous file with comments | « lib/runtime/dart/typed_data.js ('k') | lib/src/codegen/js_interop.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 js_codegen; 5 library js_codegen;
6 6
7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; 7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet;
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;
11 import 'package:analyzer/src/generated/constant.dart'; 11 import 'package:analyzer/src/generated/constant.dart';
12 import 'package:analyzer/src/generated/element.dart'; 12 import 'package:analyzer/src/generated/element.dart';
13 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
13 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; 14 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
14 import 'package:analyzer/src/generated/scanner.dart' 15 import 'package:analyzer/src/generated/scanner.dart'
15 show StringToken, Token, TokenType; 16 show StringToken, Token, TokenType;
16 import 'package:analyzer/src/generated/type_system.dart' 17 import 'package:analyzer/src/generated/type_system.dart'
17 show StrongTypeSystemImpl; 18 show StrongTypeSystemImpl;
18 import 'package:analyzer/src/task/dart.dart' show PublicNamespaceBuilder; 19 import 'package:analyzer/src/task/dart.dart' show PublicNamespaceBuilder;
19 20
20 import 'ast_builder.dart' show AstBuilder; 21 import 'ast_builder.dart' show AstBuilder;
21 import 'reify_coercions.dart' show CoercionReifier, Tuple2; 22 import 'reify_coercions.dart' show CoercionReifier, Tuple2;
22 23
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 isLazy: _isDartRuntime || !_loader.libraryIsLoaded(lib)); 212 isLazy: _isDartRuntime || !_loader.libraryIsLoaded(lib));
212 }); 213 });
213 214
214 // TODO(jmesserly): scriptTag support. 215 // TODO(jmesserly): scriptTag support.
215 // Enable this if we know we're targetting command line environment? 216 // Enable this if we know we're targetting command line environment?
216 // It doesn't work in browser. 217 // It doesn't work in browser.
217 // var jsBin = compiler.options.runnerOptions.v8Binary; 218 // var jsBin = compiler.options.runnerOptions.v8Binary;
218 // String scriptTag = null; 219 // String scriptTag = null;
219 // if (library.library.scriptTag != null) scriptTag = '/usr/bin/env $jsBin'; 220 // if (library.library.scriptTag != null) scriptTag = '/usr/bin/env $jsBin';
220 return moduleBuilder.build( 221 return moduleBuilder.build(
221 currentModuleName, 222 currentModuleName, _jsModuleValue, _exportsVar, items);
222 _jsModuleValue,
223 _exportsVar,
224 items);
225 } 223 }
226 224
227 void _emitModuleItem(AstNode node) { 225 void _emitModuleItem(AstNode node) {
228 // Attempt to group adjacent properties. 226 // Attempt to group adjacent properties.
229 if (node is! FunctionDeclaration) _flushLibraryProperties(_moduleItems); 227 if (node is! FunctionDeclaration) _flushLibraryProperties(_moduleItems);
230 228
231 var code = _visit(node); 229 var code = _visit(node);
232 if (code != null) _moduleItems.add(code); 230 if (code != null) _moduleItems.add(code);
233 } 231 }
234 232
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 } 430 }
433 431
434 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), 432 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name),
435 _classHeritage(classElem), _emitClassMethods(node, ctors, fields), 433 _classHeritage(classElem), _emitClassMethods(node, ctors, fields),
436 typeParams: _emitTypeParams(classElem).toList(), 434 typeParams: _emitTypeParams(classElem).toList(),
437 fields: 435 fields:
438 _emitFieldDeclarations(classElem, fields, staticFields).toList()); 436 _emitFieldDeclarations(classElem, fields, staticFields).toList());
439 437
440 String jsPeerName; 438 String jsPeerName;
441 var jsPeer = findAnnotation(classElem, isJsPeerInterface); 439 var jsPeer = findAnnotation(classElem, isJsPeerInterface);
440 // Only look at "Native" annotations on registered extension types.
441 // E.g., we're current ignoring the ones in dart:html.
442 if (jsPeer == null && _extensionTypes.contains(classElem)) {
443 jsPeer = findAnnotation(classElem, isNativeAnnotation);
444 }
442 if (jsPeer != null) { 445 if (jsPeer != null) {
443 jsPeerName = 446 jsPeerName =
444 getConstantField(jsPeer, 'name', types.stringType)?.toStringValue(); 447 getConstantField(jsPeer, 'name', types.stringType)?.toStringValue();
448 if (jsPeerName.contains(',')) {
449 jsPeerName = jsPeerName.split(',')[0];
450 }
445 } 451 }
446 452
447 var body = _finishClassMembers(classElem, classExpr, ctors, fields, 453 var body = _finishClassMembers(classElem, classExpr, ctors, fields,
448 staticFields, methods, node.metadata, jsPeerName); 454 staticFields, methods, node.metadata, jsPeerName);
449 455
450 var result = _finishClassDef(type, body); 456 var result = _finishClassDef(type, body);
451 457
452 if (jsPeerName != null) { 458 if (jsPeerName != null) {
453 // This class isn't allowed to be lazy, because we need to set up 459 // This class isn't allowed to be lazy, because we need to set up
454 // the native JS type eagerly at this point. 460 // the native JS type eagerly at this point.
(...skipping 860 matching lines...) Expand 10 before | Expand all | Expand 10 after
1315 t is ParameterizedType && t.typeArguments.any(_hasUnsoundTypeParameter); 1321 t is ParameterizedType && t.typeArguments.any(_hasUnsoundTypeParameter);
1316 1322
1317 JS.Expression _defaultParamValue(FormalParameter param) { 1323 JS.Expression _defaultParamValue(FormalParameter param) {
1318 if (param is DefaultFormalParameter && param.defaultValue != null) { 1324 if (param is DefaultFormalParameter && param.defaultValue != null) {
1319 return _visit(param.defaultValue); 1325 return _visit(param.defaultValue);
1320 } else { 1326 } else {
1321 return new JS.LiteralNull(); 1327 return new JS.LiteralNull();
1322 } 1328 }
1323 } 1329 }
1324 1330
1331 JS.Fun _emitNativeFunctionBody(
1332 List<JS.Parameter> params, MethodDeclaration node) {
1333 if (node.isStatic) {
1334 // TODO(vsm): Do we need to handle this case?
1335 return null;
1336 }
1337
1338 String name = node.name.name;
1339 var annotation = findAnnotation(node.element, isJsName);
1340 if (annotation != null) {
1341 name = getConstantField(annotation, 'name', types.stringType)
1342 ?.toStringValue();
1343 }
1344 if (node.isGetter) {
1345 return new JS.Fun(params, js.statement('{ return this.#; }', [name]));
1346 } else if (node.isSetter) {
1347 return new JS.Fun(
1348 params, js.statement('{ this.# = #; }', [name, params.last]));
1349 } else {
1350 return new JS.Fun(
1351 params, js.statement('{ return this.#(#); }', [name, params]));
1352 }
1353 }
1354
1325 JS.Method _emitMethodDeclaration(DartType type, MethodDeclaration node) { 1355 JS.Method _emitMethodDeclaration(DartType type, MethodDeclaration node) {
1326 if (node.isAbstract || _externalOrNative(node)) { 1356 if (node.isAbstract) {
1327 return null; 1357 return null;
1328 } 1358 }
1329 1359
1330 var params = _visit(node.parameters) as List<JS.Parameter>; 1360 var params = _visit(node.parameters) as List<JS.Parameter>;
1331 if (params == null) params = <JS.Parameter>[]; 1361 if (params == null) params = <JS.Parameter>[];
1332 1362
1333 var typeParams = _emitTypeParams(node.element).toList(); 1363 JS.Fun fn;
1334 var returnType = emitTypeRef(node.element.returnType); 1364 if (_externalOrNative(node)) {
1335 JS.Fun fn = _emitFunctionBody(params, node.body, typeParams, returnType); 1365 fn = _emitNativeFunctionBody(params, node);
1366 // TODO(vsm): Remove if / when we handle the static case above.
1367 if (fn == null) return null;
1368 } else {
1369 var typeParams = _emitTypeParams(node.element).toList();
1370 var returnType = emitTypeRef(node.element.returnType);
1371 fn = _emitFunctionBody(params, node.body, typeParams, returnType);
1372 }
1373
1336 if (node.operatorKeyword != null && 1374 if (node.operatorKeyword != null &&
1337 node.name.name == '[]=' && 1375 node.name.name == '[]=' &&
1338 params.isNotEmpty) { 1376 params.isNotEmpty) {
1339 // []= methods need to return the value. We could also address this at 1377 // []= methods need to return the value. We could also address this at
1340 // call sites, but it's cleaner to instead transform the operator method. 1378 // call sites, but it's cleaner to instead transform the operator method.
1341 var returnValue = new JS.Return(params.last); 1379 var returnValue = new JS.Return(params.last);
1342 var body = fn.body; 1380 var body = fn.body;
1343 if (JS.Return.foundIn(fn)) { 1381 if (JS.Return.foundIn(fn)) {
1344 // If a return is inside body, transform `(params) { body }` to 1382 // If a return is inside body, transform `(params) { body }` to
1345 // `(params) { (() => { body })(); return value; }`. 1383 // `(params) { (() => { body })(); return value; }`.
(...skipping 1578 matching lines...) Expand 10 before | Expand all | Expand 10 after
2924 return AstBuilder.methodInvoke( 2962 return AstBuilder.methodInvoke(
2925 newTarget, invoke.methodName, invoke.argumentList.arguments); 2963 newTarget, invoke.methodName, invoke.argumentList.arguments);
2926 } 2964 }
2927 } 2965 }
2928 2966
2929 bool _requiresStaticDispatch(Expression target, String memberName) { 2967 bool _requiresStaticDispatch(Expression target, String memberName) {
2930 var type = getStaticType(target); 2968 var type = getStaticType(target);
2931 if (!_isObjectProperty(memberName)) { 2969 if (!_isObjectProperty(memberName)) {
2932 return false; 2970 return false;
2933 } 2971 }
2934 if (!type.isObject && !_isJSBuiltinType(type) && !_isNullable(target)) { 2972 if (!type.isObject &&
2973 !_isJSBuiltinType(type) &&
2974 !_extensionTypes.contains(type.element) &&
2975 !_isNullable(target)) {
2935 return false; 2976 return false;
2936 } 2977 }
2937 return true; 2978 return true;
2938 } 2979 }
2939 2980
2940 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. 2981 /// Shared code for [PrefixedIdentifier] and [PropertyAccess].
2941 JS.Expression _emitGet(Expression target, SimpleIdentifier memberId) { 2982 JS.Expression _emitGet(Expression target, SimpleIdentifier memberId) {
2942 var member = memberId.staticElement; 2983 var member = memberId.staticElement;
2943 if (member is PropertyAccessorElement) { 2984 if (member is PropertyAccessorElement) {
2944 member = (member as PropertyAccessorElement).variable; 2985 member = (member as PropertyAccessorElement).variable;
(...skipping 673 matching lines...) Expand 10 before | Expand all | Expand 10 after
3618 } else if (type is InterfaceType && type.element == expectedType.element) { 3659 } else if (type is InterfaceType && type.element == expectedType.element) {
3619 return type.typeArguments[0]; 3660 return type.typeArguments[0];
3620 } else { 3661 } else {
3621 // TODO(leafp): The above only handles the case where the return type 3662 // TODO(leafp): The above only handles the case where the return type
3622 // is exactly Future/Stream/Iterable. Handle the subtype case. 3663 // is exactly Future/Stream/Iterable. Handle the subtype case.
3623 return DynamicTypeImpl.instance; 3664 return DynamicTypeImpl.instance;
3624 } 3665 }
3625 } 3666 }
3626 } 3667 }
3627 3668
3628 class JSGenerator extends CodeGenerator { 3669 class _ExtensionFinder extends GeneralizingElementVisitor {
3629 final _extensionTypes = new HashSet<ClassElement>(); 3670 final AnalysisContext _context;
3671 final HashSet<ClassElement> _extensionTypes;
3630 final TypeProvider _types; 3672 final TypeProvider _types;
3631 JSGenerator(AbstractCompiler compiler) 3673
3632 : _types = compiler.context.typeProvider, 3674 _ExtensionFinder(this._context, this._extensionTypes, this._types);
3633 super(compiler) { 3675
3634 // TODO(jacobr): determine the the set of types with extension methods from 3676 visitClassElement(ClassElement element) {
3635 // the annotations rather than hard coding the list once the analyzer 3677 if (findAnnotation(element, isJsPeerInterface) != null ||
3636 // supports summaries. 3678 findAnnotation(element, isNativeAnnotation) != null) {
3637 var context = compiler.context; 3679 _addExtensionType(element.type);
3638 var src = context.sourceFactory.forUri('dart:_interceptors');
3639 var interceptors = context.computeLibraryElement(src);
3640 for (var t in ['JSArray', 'JSString', 'JSNumber', 'JSBool']) {
3641 _addExtensionType(interceptors.getType(t).type);
3642 } 3680 }
3643 // TODO(jmesserly): manually add `int` and `double`
3644 // Unfortunately our current analyzer rejects "implements int".
3645 // Fix was landed, so we can remove this hack once we're updated:
3646 // https://github.com/dart-lang/sdk/commit/d7cd11f86a02f55269fc8d9843e7758eb eeb81c8
3647 _addExtensionType(_types.intType);
3648 _addExtensionType(_types.doubleType);
3649 } 3681 }
3650 3682
3651 void _addExtensionType(InterfaceType t) { 3683 void _addExtensionType(InterfaceType t) {
3652 if (t.isObject || !_extensionTypes.add(t.element)) return; 3684 if (t.isObject || !_extensionTypes.add(t.element)) return;
3653 t = fillDynamicTypeArgs(t, _types) as InterfaceType; 3685 t = fillDynamicTypeArgs(t, _types) as InterfaceType;
3654 t.interfaces.forEach(_addExtensionType); 3686 t.interfaces.forEach(_addExtensionType);
3655 t.mixins.forEach(_addExtensionType); 3687 t.mixins.forEach(_addExtensionType);
3656 _addExtensionType(t.superclass); 3688 _addExtensionType(t.superclass);
3657 } 3689 }
3658 3690
3691 void _addExtensionTypes(String libraryUri) {
3692 var sourceFactory = _context.sourceFactory.forUri(libraryUri);
3693 var library = _context.computeLibraryElement(sourceFactory);
3694 visitLibraryElement(library);
3695 }
3696 }
3697
3698 class JSGenerator extends CodeGenerator {
3699 final _extensionTypes = new HashSet<ClassElement>();
3700 final TypeProvider _types;
3701
3702 JSGenerator(AbstractCompiler compiler)
3703 : _types = compiler.context.typeProvider,
3704 super(compiler) {
3705 // TODO(vsm): Eventually, we want to make this extensible - i.e., find
3706 // annotations in user code as well. It would need to be summarized in
3707 // the element model - not searched this way on every compile.
3708 var finder = new _ExtensionFinder(context, _extensionTypes, _types);
3709 finder._addExtensionTypes('dart:_interceptors');
3710 finder._addExtensionTypes('dart:_native_typed_data');
3711
3712 // TODO(vsm): If we're analyzing against the main SDK, those
3713 // types are not explicitly annotated.
3714 finder._addExtensionType(_types.intType);
3715 finder._addExtensionType(_types.doubleType);
3716 finder._addExtensionType(_types.boolType);
3717 finder._addExtensionType(_types.stringType);
3718 }
3719
3659 String generateLibrary(LibraryUnit unit) { 3720 String generateLibrary(LibraryUnit unit) {
3660 // Clone the AST first, so we can mutate it. 3721 // Clone the AST first, so we can mutate it.
3661 unit = unit.clone(); 3722 unit = unit.clone();
3662 var library = unit.library.element.library; 3723 var library = unit.library.element.library;
3663 var fields = findFieldsNeedingStorage(unit, _extensionTypes); 3724 var fields = findFieldsNeedingStorage(unit, _extensionTypes);
3664 var rules = new StrongTypeSystemImpl(); 3725 var rules = new StrongTypeSystemImpl();
3665 var codegen = 3726 var codegen =
3666 new JSCodegenVisitor(compiler, rules, library, _extensionTypes, fields); 3727 new JSCodegenVisitor(compiler, rules, library, _extensionTypes, fields);
3667 var module = codegen.emitLibrary(unit); 3728 var module = codegen.emitLibrary(unit);
3668 var out = compiler.getOutputPath(library.source.uri); 3729 var out = compiler.getOutputPath(library.source.uri);
(...skipping 25 matching lines...) Expand all
3694 3755
3695 /// A special kind of element created by the compiler, signifying a temporary 3756 /// A special kind of element created by the compiler, signifying a temporary
3696 /// variable. These objects use instance equality, and should be shared 3757 /// variable. These objects use instance equality, and should be shared
3697 /// everywhere in the tree where they are treated as the same variable. 3758 /// everywhere in the tree where they are treated as the same variable.
3698 class TemporaryVariableElement extends LocalVariableElementImpl { 3759 class TemporaryVariableElement extends LocalVariableElementImpl {
3699 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); 3760 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name);
3700 3761
3701 int get hashCode => identityHashCode(this); 3762 int get hashCode => identityHashCode(this);
3702 bool operator ==(Object other) => identical(this, other); 3763 bool operator ==(Object other) => identical(this, other);
3703 } 3764 }
OLDNEW
« no previous file with comments | « lib/runtime/dart/typed_data.js ('k') | lib/src/codegen/js_interop.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698