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

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

Issue 1700153002: Wrapperless dart:html and friends (Closed) Base URL: https://github.com/dart-lang/dev_compiler.git@master
Patch Set: A couple more tweaks 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/web_sql.js ('k') | lib/src/compiler.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/dart/ast/token.dart'; 10 import 'package:analyzer/dart/ast/token.dart';
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after
637 if (type.mixins.isNotEmpty) { 637 if (type.mixins.isNotEmpty) {
638 var mixins = type.mixins.map(_emitTypeName).toList(); 638 var mixins = type.mixins.map(_emitTypeName).toList();
639 mixins.insert(0, heritage); 639 mixins.insert(0, heritage);
640 heritage = js.call('dart.mixin(#)', [mixins]); 640 heritage = js.call('dart.mixin(#)', [mixins]);
641 } 641 }
642 642
643 _loader.finishTopLevel(element); 643 _loader.finishTopLevel(element);
644 return heritage; 644 return heritage;
645 } 645 }
646 646
647 /// Provide Dart getters and setters that forward to the underlying native
648 /// field. Note that the Dart names are always symbolized to avoid
649 /// conflicts. They will be installed as extension methods on the underlying
650 /// native type.
651 List<JS.Method> _emitNativeFieldAccessors(FieldDeclaration node) {
652 // TODO(vsm): Can this by meta-programmed?
653 // E.g., dart.nativeField(symbol, jsName)
654 // Alternatively, perhaps it could be meta-programmed directly in
655 // dart.registerExtensions?
656 var jsMethods = <JS.Method>[];
657 if (!node.isStatic) {
658 for (var decl in node.fields.variables) {
659 var field = decl.element;
660 var name = decl.name.name;
661 var annotation = findAnnotation(field, isJsName);
662 if (annotation != null) {
663 name = getConstantField(annotation, 'name', types.stringType)
664 ?.toStringValue();
665 }
666 // Generate getter
667 var fn = new JS.Fun([], js.statement('{ return this.#; }', [name]));
668 var method =
669 new JS.Method(_elementMemberName(field.getter), fn, isGetter: true);
670 jsMethods.add(method);
671
672 // Generate setter
673 if (!decl.isFinal) {
674 var value = new JS.TemporaryId('value');
675 fn = new JS.Fun(
676 [value], js.statement('{ this.# = #; }', [name, value]));
677 method = new JS.Method(_elementMemberName(field.setter), fn,
678 isSetter: true);
679 jsMethods.add(method);
680 }
681 }
682 }
683 return jsMethods;
684 }
685
647 List<JS.Method> _emitClassMethods(ClassDeclaration node, 686 List<JS.Method> _emitClassMethods(ClassDeclaration node,
648 List<ConstructorDeclaration> ctors, List<FieldDeclaration> fields) { 687 List<ConstructorDeclaration> ctors, List<FieldDeclaration> fields) {
649 var element = node.element; 688 var element = node.element;
650 var type = element.type; 689 var type = element.type;
651 var isObject = type.isObject; 690 var isObject = type.isObject;
652 691
653 // Iff no constructor is specified for a class C, it implicitly has a 692 // Iff no constructor is specified for a class C, it implicitly has a
654 // default constructor `C() : super() {}`, unless C is class Object. 693 // default constructor `C() : super() {}`, unless C is class Object.
655 var jsMethods = <JS.Method>[]; 694 var jsMethods = <JS.Method>[];
656 if (ctors.isEmpty && !isObject) { 695 if (ctors.isEmpty && !isObject) {
657 jsMethods.add(_emitImplicitConstructor(node, fields)); 696 jsMethods.add(_emitImplicitConstructor(node, fields));
658 } 697 }
659 698
660 bool hasJsPeer = findAnnotation(element, isJsPeerInterface) != null; 699 bool hasJsPeer = findAnnotation(element, isJsPeerInterface) != null;
661 700
662 bool hasIterator = false; 701 bool hasIterator = false;
663 for (var m in node.members) { 702 for (var m in node.members) {
664 if (m is ConstructorDeclaration) { 703 if (m is ConstructorDeclaration) {
665 jsMethods.add(_emitConstructor(m, type, fields, isObject)); 704 jsMethods.add(_emitConstructor(m, type, fields, isObject));
666 } else if (m is MethodDeclaration) { 705 } else if (m is MethodDeclaration) {
667 jsMethods.add(_emitMethodDeclaration(type, m)); 706 jsMethods.add(_emitMethodDeclaration(type, m));
668 707
669 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') { 708 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') {
670 hasIterator = true; 709 hasIterator = true;
671 jsMethods.add(_emitIterable(type)); 710 jsMethods.add(_emitIterable(type));
672 } 711 }
712 } else if (m is FieldDeclaration && _extensionTypes.contains(element)) {
713 jsMethods.addAll(_emitNativeFieldAccessors(m));
673 } 714 }
674 } 715 }
675 716
676 // If the type doesn't have an `iterator`, but claims to implement Iterable, 717 // If the type doesn't have an `iterator`, but claims to implement Iterable,
677 // we inject the adaptor method here, as it's less code size to put the 718 // we inject the adaptor method here, as it's less code size to put the
678 // helper on a parent class. This pattern is common in the core libraries 719 // helper on a parent class. This pattern is common in the core libraries
679 // (e.g. IterableMixin<E> and IterableBase<E>). 720 // (e.g. IterableMixin<E> and IterableBase<E>).
680 // 721 //
681 // (We could do this same optimization for any interface with an `iterator` 722 // (We could do this same optimization for any interface with an `iterator`
682 // method, but that's more expensive to check for, so it doesn't seem worth 723 // method, but that's more expensive to check for, so it doesn't seem worth
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
763 var name = classElem.name; 804 var name = classElem.name;
764 var body = <JS.Statement>[]; 805 var body = <JS.Statement>[];
765 806
766 if (_extensionTypes.contains(classElem)) { 807 if (_extensionTypes.contains(classElem)) {
767 var dartxNames = <JS.Expression>[]; 808 var dartxNames = <JS.Expression>[];
768 for (var m in methods) { 809 for (var m in methods) {
769 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { 810 if (!m.isAbstract && !m.isStatic && m.element.isPublic) {
770 dartxNames.add(_elementMemberName(m.element, allowExtensions: false)); 811 dartxNames.add(_elementMemberName(m.element, allowExtensions: false));
771 } 812 }
772 } 813 }
814 for (var f in fields) {
815 if (!f.isStatic) {
816 for (var d in f.fields.variables) {
817 if (d.element.isPublic) {
818 dartxNames.add(
819 _elementMemberName(d.element.getter, allowExtensions: false));
820 }
821 }
822 }
823 }
773 if (dartxNames.isNotEmpty) { 824 if (dartxNames.isNotEmpty) {
774 body.add(js.statement('dart.defineExtensionNames(#)', 825 body.add(js.statement('dart.defineExtensionNames(#)',
775 [new JS.ArrayInitializer(dartxNames, multiline: true)])); 826 [new JS.ArrayInitializer(dartxNames, multiline: true)]));
776 } 827 }
777 } 828 }
778 829
779 body.add(_emitClassHeritageWorkaround(cls)); 830 body.add(_emitClassHeritageWorkaround(cls));
780 831
781 // TODO(jmesserly): we should really just extend native Array. 832 // TODO(jmesserly): we should really just extend native Array.
782 if (jsPeerName != null && classElem.typeParameters.isNotEmpty) { 833 if (jsPeerName != null && classElem.typeParameters.isNotEmpty) {
(...skipping 2203 matching lines...) Expand 10 before | Expand all | Expand 10 after
2986 return AstBuilder.methodInvoke( 3037 return AstBuilder.methodInvoke(
2987 newTarget, invoke.methodName, invoke.argumentList.arguments); 3038 newTarget, invoke.methodName, invoke.argumentList.arguments);
2988 } 3039 }
2989 } 3040 }
2990 3041
2991 bool _requiresStaticDispatch(Expression target, String memberName) { 3042 bool _requiresStaticDispatch(Expression target, String memberName) {
2992 var type = getStaticType(target); 3043 var type = getStaticType(target);
2993 if (!_isObjectProperty(memberName)) { 3044 if (!_isObjectProperty(memberName)) {
2994 return false; 3045 return false;
2995 } 3046 }
2996 if (!type.isObject && 3047
2997 !_isJSBuiltinType(type) && 3048 // If the target could be `null`, we need static dispatch.
2998 !_extensionTypes.contains(type.element) && 3049 // If the target may be an extension type, we also use static dispatch
2999 !_isNullable(target)) { 3050 // as we don't symbolize object properties like hashCode.
3000 return false; 3051 return _isNullable(target) ||
3001 } 3052 (_extensionTypes.contains(type.element) && target is! SuperExpression);
3002 return true;
3003 } 3053 }
3004 3054
3005 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. 3055 /// Shared code for [PrefixedIdentifier] and [PropertyAccess].
3006 JS.Expression _emitGet(Expression target, SimpleIdentifier memberId) { 3056 JS.Expression _emitGet(Expression target, SimpleIdentifier memberId) {
3007 var member = memberId.staticElement; 3057 var member = memberId.staticElement;
3008 if (member is PropertyAccessorElement) { 3058 if (member is PropertyAccessorElement) {
3009 member = (member as PropertyAccessorElement).variable; 3059 member = (member as PropertyAccessorElement).variable;
3010 } 3060 }
3011 bool isStatic = member is ClassMemberElement && member.isStatic; 3061 bool isStatic = member is ClassMemberElement && member.isStatic;
3012 var name = _emitMemberName(memberId.name, 3062 var name = _emitMemberName(memberId.name,
(...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after
3579 // conflict. We could use practically any character for this. 3629 // conflict. We could use practically any character for this.
3580 name = '+$name'; 3630 name = '+$name';
3581 } 3631 }
3582 3632
3583 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. 3633 // Dart "extension" methods. Used for JS Array, Boolean, Number, String.
3584 var baseType = type; 3634 var baseType = type;
3585 while (baseType is TypeParameterType) { 3635 while (baseType is TypeParameterType) {
3586 baseType = baseType.element.bound; 3636 baseType = baseType.element.bound;
3587 } 3637 }
3588 if (allowExtensions && 3638 if (allowExtensions &&
3639 baseType != null &&
3589 _extensionTypes.contains(baseType.element) && 3640 _extensionTypes.contains(baseType.element) &&
3590 !_isObjectProperty(name)) { 3641 !_isObjectProperty(name)) {
3591 return js.call('dartx.#', _propertyName(name)); 3642 return js.call('dartx.#', _propertyName(name));
3592 } 3643 }
3593 3644
3594 return _propertyName(name); 3645 return _propertyName(name);
3595 } 3646 }
3596 3647
3597 bool _externalOrNative(node) => 3648 bool _externalOrNative(node) =>
3598 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; 3649 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody;
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
3725 3776
3726 JSGenerator(AbstractCompiler compiler) 3777 JSGenerator(AbstractCompiler compiler)
3727 : _types = compiler.context.typeProvider, 3778 : _types = compiler.context.typeProvider,
3728 super(compiler) { 3779 super(compiler) {
3729 // TODO(vsm): Eventually, we want to make this extensible - i.e., find 3780 // TODO(vsm): Eventually, we want to make this extensible - i.e., find
3730 // annotations in user code as well. It would need to be summarized in 3781 // annotations in user code as well. It would need to be summarized in
3731 // the element model - not searched this way on every compile. 3782 // the element model - not searched this way on every compile.
3732 var finder = new _ExtensionFinder(context, _extensionTypes, _types); 3783 var finder = new _ExtensionFinder(context, _extensionTypes, _types);
3733 finder._addExtensionTypes('dart:_interceptors'); 3784 finder._addExtensionTypes('dart:_interceptors');
3734 finder._addExtensionTypes('dart:_native_typed_data'); 3785 finder._addExtensionTypes('dart:_native_typed_data');
3786 finder._addExtensionTypes('dart:html');
3787 finder._addExtensionTypes('dart:indexed_db');
3788 finder._addExtensionTypes('dart:svg');
3789 finder._addExtensionTypes('dart:web_audio');
3790 finder._addExtensionTypes('dart:web_gl');
3791 finder._addExtensionTypes('dart:web_sql');
3735 3792
3736 // TODO(vsm): If we're analyzing against the main SDK, those 3793 // TODO(vsm): If we're analyzing against the main SDK, those
3737 // types are not explicitly annotated. 3794 // types are not explicitly annotated.
3738 finder._addExtensionType(_types.intType); 3795 finder._addExtensionType(_types.intType);
3739 finder._addExtensionType(_types.doubleType); 3796 finder._addExtensionType(_types.doubleType);
3740 finder._addExtensionType(_types.boolType); 3797 finder._addExtensionType(_types.boolType);
3741 finder._addExtensionType(_types.stringType); 3798 finder._addExtensionType(_types.stringType);
3742 } 3799 }
3743 3800
3744 String generateLibrary(LibraryUnit unit) { 3801 String generateLibrary(LibraryUnit unit) {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
3779 3836
3780 /// A special kind of element created by the compiler, signifying a temporary 3837 /// A special kind of element created by the compiler, signifying a temporary
3781 /// variable. These objects use instance equality, and should be shared 3838 /// variable. These objects use instance equality, and should be shared
3782 /// everywhere in the tree where they are treated as the same variable. 3839 /// everywhere in the tree where they are treated as the same variable.
3783 class TemporaryVariableElement extends LocalVariableElementImpl { 3840 class TemporaryVariableElement extends LocalVariableElementImpl {
3784 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); 3841 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name);
3785 3842
3786 int get hashCode => identityHashCode(this); 3843 int get hashCode => identityHashCode(this);
3787 bool operator ==(Object other) => identical(this, other); 3844 bool operator ==(Object other) => identical(this, other);
3788 } 3845 }
OLDNEW
« no previous file with comments | « lib/runtime/dart/web_sql.js ('k') | lib/src/compiler.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698