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

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

Issue 1141663003: fixes #185, track const ctor dependencies, plus a static field fix (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: format Created 5 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 unified diff | Download patch
« no previous file with comments | « lib/runtime/dart/convert.js ('k') | lib/src/dependency_graph.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 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 651 matching lines...) Expand 10 before | Expand all | Expand 10 after
662 _visit(node.redirectedConstructor), 662 _visit(node.redirectedConstructor),
663 _visit(node.parameters) 663 _visit(node.parameters)
664 ]); 664 ]);
665 } 665 }
666 666
667 var body = <JS.Statement>[]; 667 var body = <JS.Statement>[];
668 668
669 // Generate optional/named argument value assignment. These can not have 669 // Generate optional/named argument value assignment. These can not have
670 // side effects, and may be used by the constructor's initializers, so it's 670 // side effects, and may be used by the constructor's initializers, so it's
671 // nice to do them first. 671 // nice to do them first.
672 // Also for const constructors we need to ensure default values are
673 // available for use by top-level constant initializers.
674 ClassDeclaration cls = node.parent;
675 if (node.constKeyword != null) _loader.startTopLevel(cls.element);
672 var init = _emitArgumentInitializers(node, constructor: true); 676 var init = _emitArgumentInitializers(node, constructor: true);
677 if (node.constKeyword != null) _loader.finishTopLevel(cls.element);
673 if (init != null) body.add(init); 678 if (init != null) body.add(init);
674 679
675 // Redirecting constructors: these are not allowed to have initializers, 680 // Redirecting constructors: these are not allowed to have initializers,
676 // and the redirecting ctor invocation runs before field initializers. 681 // and the redirecting ctor invocation runs before field initializers.
677 var redirectCall = node.initializers.firstWhere( 682 var redirectCall = node.initializers.firstWhere(
678 (i) => i is RedirectingConstructorInvocation, orElse: () => null); 683 (i) => i is RedirectingConstructorInvocation, orElse: () => null);
679 684
680 if (redirectCall != null) { 685 if (redirectCall != null) {
681 body.add(_visit(redirectCall)); 686 body.add(_visit(redirectCall));
682 return new JS.Block(body); 687 return new JS.Block(body);
683 } 688 }
684 689
685 // Initializers only run for non-factory constructors. 690 // Initializers only run for non-factory constructors.
686 if (node.factoryKeyword == null) { 691 if (node.factoryKeyword == null) {
687 // Generate field initializers. 692 // Generate field initializers.
688 // These are expanded into each non-redirecting constructor. 693 // These are expanded into each non-redirecting constructor.
689 // In the future we may want to create an initializer function if we have 694 // In the future we may want to create an initializer function if we have
690 // multiple constructors, but it needs to be balanced against readability. 695 // multiple constructors, but it needs to be balanced against readability.
691 body.add(_initializeFields(node, fields)); 696 body.add(_initializeFields(node.parent, fields, node));
692 697
693 var superCall = node.initializers.firstWhere( 698 var superCall = node.initializers.firstWhere(
694 (i) => i is SuperConstructorInvocation, orElse: () => null); 699 (i) => i is SuperConstructorInvocation, orElse: () => null);
695 700
696 // If no superinitializer is provided, an implicit superinitializer of the 701 // If no superinitializer is provided, an implicit superinitializer of the
697 // form `super()` is added at the end of the initializer list, unless the 702 // form `super()` is added at the end of the initializer list, unless the
698 // enclosing class is class Object. 703 // enclosing class is class Object.
699 var jsSuper = _superConstructorCall(node.parent, superCall); 704 var jsSuper = _superConstructorCall(node.parent, superCall);
700 if (jsSuper != null) body.add(jsSuper); 705 if (jsSuper != null) body.add(jsSuper);
701 } 706 }
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
746 return e.fields.any((f) => !f.isStatic && !f.isSynthetic); 751 return e.fields.any((f) => !f.isStatic && !f.isSynthetic);
747 } 752 }
748 753
749 /// Initialize fields. They follow the sequence: 754 /// Initialize fields. They follow the sequence:
750 /// 755 ///
751 /// 1. field declaration initializer if non-const, 756 /// 1. field declaration initializer if non-const,
752 /// 2. field initializing parameters, 757 /// 2. field initializing parameters,
753 /// 3. constructor field initializers, 758 /// 3. constructor field initializers,
754 /// 4. initialize fields not covered in 1-3 759 /// 4. initialize fields not covered in 1-3
755 JS.Statement _initializeFields( 760 JS.Statement _initializeFields(
756 AstNode node, List<FieldDeclaration> fieldDecls) { 761 ClassDeclaration cls, List<FieldDeclaration> fieldDecls,
757 var unit = node.getAncestor((a) => a is CompilationUnit); 762 [ConstructorDeclaration ctor]) {
763 var unit = cls.getAncestor((a) => a is CompilationUnit);
758 var constField = new ConstFieldVisitor(types, unit); 764 var constField = new ConstFieldVisitor(types, unit);
765 bool isConst = ctor != null && ctor.constKeyword != null;
766 if (isConst) _loader.startTopLevel(cls.element);
759 767
760 // Run field initializers if they can have side-effects. 768 // Run field initializers if they can have side-effects.
761 var fields = new Map<FieldElement, JS.Expression>(); 769 var fields = new Map<FieldElement, JS.Expression>();
762 var unsetFields = new Map<FieldElement, VariableDeclaration>(); 770 var unsetFields = new Map<FieldElement, VariableDeclaration>();
763 for (var declaration in fieldDecls) { 771 for (var declaration in fieldDecls) {
764 for (var fieldNode in declaration.fields.variables) { 772 for (var fieldNode in declaration.fields.variables) {
765 var element = fieldNode.element; 773 var element = fieldNode.element;
766 if (constField.isFieldInitConstant(fieldNode)) { 774 if (constField.isFieldInitConstant(fieldNode)) {
767 unsetFields[element] = fieldNode; 775 unsetFields[element] = fieldNode;
768 } else { 776 } else {
769 fields[element] = _visitInitializer(fieldNode); 777 fields[element] = _visitInitializer(fieldNode);
770 } 778 }
771 } 779 }
772 } 780 }
773 781
774 // Initialize fields from `this.fieldName` parameters. 782 // Initialize fields from `this.fieldName` parameters.
775 if (node is ConstructorDeclaration) { 783 if (ctor != null) {
776 var parameters = node.parameters; 784 for (var p in ctor.parameters.parameters) {
777 var initializers = node.initializers;
778
779 for (var p in parameters.parameters) {
780 var element = p.element; 785 var element = p.element;
781 if (element is FieldFormalParameterElement) { 786 if (element is FieldFormalParameterElement) {
782 fields[element.field] = _visit(p); 787 fields[element.field] = _visit(p);
783 } 788 }
784 } 789 }
785 790
786 // Run constructor field initializers such as `: foo = bar.baz` 791 // Run constructor field initializers such as `: foo = bar.baz`
787 for (var init in initializers) { 792 for (var init in ctor.initializers) {
788 if (init is ConstructorFieldInitializer) { 793 if (init is ConstructorFieldInitializer) {
789 fields[init.fieldName.staticElement] = _visit(init.expression); 794 fields[init.fieldName.staticElement] = _visit(init.expression);
790 } 795 }
791 } 796 }
792 } 797 }
793 798
794 for (var f in fields.keys) unsetFields.remove(f); 799 for (var f in fields.keys) unsetFields.remove(f);
795 800
796 // Initialize all remaining fields 801 // Initialize all remaining fields
797 unsetFields.forEach((element, fieldNode) { 802 unsetFields.forEach((element, fieldNode) {
798 JS.Expression value; 803 JS.Expression value;
799 if (fieldNode.initializer != null) { 804 if (fieldNode.initializer != null) {
800 value = _visit(fieldNode.initializer); 805 value = _visit(fieldNode.initializer);
801 } else { 806 } else {
802 var type = rules.elementType(element); 807 var type = rules.elementType(element);
803 value = new JS.LiteralNull(); 808 value = new JS.LiteralNull();
804 if (rules.maybeNonNullableType(type)) { 809 if (rules.maybeNonNullableType(type)) {
805 value = js.call('dart.as(#, #)', [value, _emitTypeName(type)]); 810 value = js.call('dart.as(#, #)', [value, _emitTypeName(type)]);
806 } 811 }
807 } 812 }
808 fields[element] = value; 813 fields[element] = value;
809 }); 814 });
810 815
811 var body = <JS.Statement>[]; 816 var body = <JS.Statement>[];
812 fields.forEach((FieldElement e, JS.Expression initialValue) { 817 fields.forEach((FieldElement e, JS.Expression initialValue) {
813 var access = _emitMemberName(e.name, type: e.enclosingElement.type); 818 var access = _emitMemberName(e.name, type: e.enclosingElement.type);
814 body.add(js.statement('this.# = #;', [access, initialValue])); 819 body.add(js.statement('this.# = #;', [access, initialValue]));
815 }); 820 });
821
822 if (isConst) _loader.finishTopLevel(cls.element);
816 return _statement(body); 823 return _statement(body);
817 } 824 }
818 825
819 FormalParameterList _parametersOf(node) { 826 FormalParameterList _parametersOf(node) {
820 // TODO(jmesserly): clean this up. If we can model ES6 spread/rest args, we 827 // TODO(jmesserly): clean this up. If we can model ES6 spread/rest args, we
821 // could handle argument initializers more consistently in a separate 828 // could handle argument initializers more consistently in a separate
822 // lowering pass. 829 // lowering pass.
823 if (node is ConstructorDeclaration) return node.parameters; 830 if (node is ConstructorDeclaration) return node.parameters;
824 if (node is MethodDeclaration) return node.parameters; 831 if (node is MethodDeclaration) return node.parameters;
825 if (node is FunctionDeclaration) node = node.functionExpression; 832 if (node is FunctionDeclaration) node = node.functionExpression;
(...skipping 1057 matching lines...) Expand 10 before | Expand all | Expand 10 after
1883 !_isJSBuiltinType(type) && 1890 !_isJSBuiltinType(type) &&
1884 _isNonNullableExpression(target)) { 1891 _isNonNullableExpression(target)) {
1885 return false; 1892 return false;
1886 } 1893 }
1887 return true; 1894 return true;
1888 } 1895 }
1889 1896
1890 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. 1897 /// Shared code for [PrefixedIdentifier] and [PropertyAccess].
1891 JS.Expression _emitGet(Expression target, SimpleIdentifier memberId) { 1898 JS.Expression _emitGet(Expression target, SimpleIdentifier memberId) {
1892 var member = memberId.staticElement; 1899 var member = memberId.staticElement;
1893 bool isStatic = member is ExecutableElement && member.isStatic; 1900 if (member is PropertyAccessorElement) member = member.variable;
1901 bool isStatic = member is ClassMemberElement && member.isStatic;
1902 if (isStatic) {
1903 _loader.declareBeforeUse(member);
1904 }
1894 var name = _emitMemberName(memberId.name, 1905 var name = _emitMemberName(memberId.name,
1895 type: getStaticType(target), isStatic: isStatic); 1906 type: getStaticType(target), isStatic: isStatic);
1896 if (rules.isDynamicTarget(target)) { 1907 if (rules.isDynamicTarget(target)) {
1897 return js.call('dart.$DLOAD(#, #)', [_visit(target), name]); 1908 return js.call('dart.$DLOAD(#, #)', [_visit(target), name]);
1898 } 1909 }
1899 1910
1900 String code; 1911 String code;
1901 if (member != null && member is MethodElement) { 1912 if (member != null && member is MethodElement) {
1902 // Tear-off methods: explicitly bind it. 1913 // Tear-off methods: explicitly bind it.
1903 if (_requiresStaticDispatch(target, memberId.name)) { 1914 if (_requiresStaticDispatch(target, memberId.name)) {
(...skipping 571 matching lines...) Expand 10 before | Expand all | Expand 10 after
2475 2486
2476 /// A special kind of element created by the compiler, signifying a temporary 2487 /// A special kind of element created by the compiler, signifying a temporary
2477 /// variable. These objects use instance equality, and should be shared 2488 /// variable. These objects use instance equality, and should be shared
2478 /// everywhere in the tree where they are treated as the same variable. 2489 /// everywhere in the tree where they are treated as the same variable.
2479 class TemporaryVariableElement extends LocalVariableElementImpl { 2490 class TemporaryVariableElement extends LocalVariableElementImpl {
2480 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); 2491 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name);
2481 2492
2482 int get hashCode => identityHashCode(this); 2493 int get hashCode => identityHashCode(this);
2483 bool operator ==(Object other) => identical(this, other); 2494 bool operator ==(Object other) => identical(this, other);
2484 } 2495 }
OLDNEW
« no previous file with comments | « lib/runtime/dart/convert.js ('k') | lib/src/dependency_graph.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698