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

Side by Side Diff: pkg/compiler/lib/src/closure.dart

Issue 2964783002: Reapply "Added for-loop variable tracking and regular closures/initializers captured variable track… (Closed)
Patch Set: . Created 3 years, 5 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 | « no previous file | pkg/compiler/lib/src/js_model/closure.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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 import 'common/names.dart' show Identifiers; 5 import 'common/names.dart' show Identifiers;
6 import 'common/resolution.dart' show ParsingContext, Resolution; 6 import 'common/resolution.dart' show ParsingContext, Resolution;
7 import 'common/tasks.dart' show CompilerTask, Measurer; 7 import 'common/tasks.dart' show CompilerTask, Measurer;
8 import 'common.dart'; 8 import 'common.dart';
9 import 'compiler.dart' show Compiler; 9 import 'compiler.dart' show Compiler;
10 import 'constants/expressions.dart'; 10 import 'constants/expressions.dart';
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
77 /// Returns true if this [variable] is used inside a `try` block or a `sync*` 77 /// Returns true if this [variable] is used inside a `try` block or a `sync*`
78 /// generator (this is important to know because boxing/redirection needs to 78 /// generator (this is important to know because boxing/redirection needs to
79 /// happen for those local variables). 79 /// happen for those local variables).
80 /// 80 ///
81 /// Variables that are used in a try must be treated as boxed because the 81 /// Variables that are used in a try must be treated as boxed because the
82 /// control flow can be non-linear. 82 /// control flow can be non-linear.
83 /// 83 ///
84 /// Also parameters to a `sync*` generator must be boxed, because of the way 84 /// Also parameters to a `sync*` generator must be boxed, because of the way
85 /// we rewrite sync* functions. See also comments in 85 /// we rewrite sync* functions. See also comments in
86 /// [ClosureClassMap.useLocal]. 86 /// [ClosureClassMap.useLocal].
87 bool variableIsUsedInTryOrSync(Local variable) => false; 87 bool localIsUsedInTryOrSync(Local variable) => false;
88 88
89 /// Loop through each variable that has been defined in this scope, modified 89 /// Loop through each variable that has been defined in this scope, modified
90 /// anywhere (this scope or another scope) and used in another scope. Because 90 /// anywhere (this scope or another scope) and used in another scope. Because
91 /// it is used in another scope, these variables need to be "boxed", creating 91 /// it is used in another scope, these variables need to be "boxed", creating
92 /// a thin wrapper around accesses to these variables so that accesses get 92 /// a thin wrapper around accesses to these variables so that accesses get
93 /// the correct updated value. The variables in variablesUsedInTryOrSync may 93 /// the correct updated value. The variables in localsUsedInTryOrSync may
94 /// be included in this set. 94 /// be included in this set.
95 /// 95 ///
96 /// In the case of loops, this is the set of iteration variables (or any 96 /// In the case of loops, this is the set of iteration variables (or any
97 /// variables declared in the for loop expression (`for (...here...)`) that 97 /// variables declared in the for loop expression (`for (...here...)`) that
98 /// need to be boxed to snapshot their value. 98 /// need to be boxed to snapshot their value.
99 void forEachBoxedVariable(f(Local local, FieldEntity field)) {} 99 void forEachBoxedVariable(f(Local local, FieldEntity field)) {}
100 100
101 /// True if [variable] has been mutated and is also used in another scope. 101 /// True if [variable] has been mutated and is also used in another scope.
102 bool isBoxed(Local variable) => false; 102 bool isBoxed(Local variable) => false;
103
104 /// True if this scope declares any variables that need to be boxed.
105 bool get hasBoxedVariables => false;
106 } 103 }
107 104
108 /// Class representing the usage of a scope that has been captured in the 105 /// Class representing the usage of a scope that has been captured in the
109 /// context of a closure. 106 /// context of a closure.
110 class ClosureScope extends ScopeInfo { 107 class ClosureScope extends ScopeInfo {
111 const ClosureScope(); 108 const ClosureScope();
112 109
113 /// If true, this closure accesses a variable that was defined in an outside 110 /// If true, this closure accesses a variable that was defined in an outside
114 /// scope and this variable gets modified at some point (sometimes we say that 111 /// scope and this variable gets modified at some point (sometimes we say that
115 /// variable has been "captured"). In this situation, access to this variable 112 /// variable has been "captured"). In this situation, access to this variable
(...skipping 18 matching lines...) Expand all
134 /// var lst = []; 131 /// var lst = [];
135 /// for (int i = 0; i < 5; i++) lst.add(()=>i); 132 /// for (int i = 0; i < 5; i++) lst.add(()=>i);
136 /// var result = list.map((f) => f()).toList(); 133 /// var result = list.map((f) => f()).toList();
137 /// 134 ///
138 /// `result` will be [0, 1, 2, 3, 4], whereas were this JS code 135 /// `result` will be [0, 1, 2, 3, 4], whereas were this JS code
139 /// the result would be [5, 5, 5, 5, 5]. Because of this difference we need to 136 /// the result would be [5, 5, 5, 5, 5]. Because of this difference we need to
140 /// create a closure for these sorts of loops to capture the variable's value at 137 /// create a closure for these sorts of loops to capture the variable's value at
141 /// each iteration, by boxing the iteration variable[s]. 138 /// each iteration, by boxing the iteration variable[s].
142 class LoopClosureScope extends ClosureScope { 139 class LoopClosureScope extends ClosureScope {
143 const LoopClosureScope(); 140 const LoopClosureScope();
141
142 /// True if this loop scope declares in the first part of the loop
143 /// `for (<here>;...;...)` any variables that need to be boxed.
144 bool get hasBoxedLoopVariables => false;
145
146 /// The set of iteration variables (or variables declared in the for loop
147 /// expression (`for (<here>; ... ; ...)`) that need to be boxed to snapshot
148 /// their value. These variables are also included in the set of
149 /// `forEachBoxedVariable` method. The distinction between these two sets is
150 /// in this example:
151 ///
152 /// run(f) => f();
153 /// var a;
154 /// for (int i = 0; i < 3; i++) {
155 /// var b = 3;
156 /// a = () => b = i;
157 /// }
158 ///
159 /// `i` would be a part of the boxedLoopVariables AND boxedVariables, but b
160 /// would only be a part of boxedVariables.
161 List<Local> get boxedLoopVariables => const <Local>[];
144 } 162 }
145 163
146 /// Class that describes the actual mechanics of how the converted, rewritten 164 /// Class that describes the actual mechanics of how the converted, rewritten
147 /// closure is implemented. For example, for the following closure (named foo 165 /// closure is implemented. For example, for the following closure (named foo
148 /// for convenience): 166 /// for convenience):
149 /// 167 ///
150 /// var foo = (x) => y + x; 168 /// var foo = (x) => y + x;
151 /// 169 ///
152 /// We would produce the following class to control access to these variables in 170 /// We would produce the following class to control access to these variables in
153 /// the following way (modulo naming of variables, assuming that y is modified 171 /// the following way (modulo naming of variables, assuming that y is modified
(...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after
640 // Otherwise contains the empty List. 658 // Otherwise contains the empty List.
641 List<Local> boxedLoopVariables = const <Local>[]; 659 List<Local> boxedLoopVariables = const <Local>[];
642 660
643 ClosureScopeImpl(this.boxElement, this.capturedVariables); 661 ClosureScopeImpl(this.boxElement, this.capturedVariables);
644 662
645 Local get context => boxElement; 663 Local get context => boxElement;
646 664
647 bool get requiresContextBox => capturedVariables.keys.isNotEmpty; 665 bool get requiresContextBox => capturedVariables.keys.isNotEmpty;
648 666
649 void forEachBoxedVariable(f(Local local, FieldEntity field)) { 667 void forEachBoxedVariable(f(Local local, FieldEntity field)) {
650 if (capturedVariables.isNotEmpty) { 668 capturedVariables.forEach(f);
651 capturedVariables.forEach(f);
652 } else {
653 for (Local l in boxedLoopVariables) {
654 // The boxes for loop variables are constructed on-demand per-iteration
655 // in the locals handler.
656 f(l, null);
657 }
658 }
659 } 669 }
660 670
661 bool get hasBoxedVariables => !capturedVariables.isEmpty; 671 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
662 672
663 bool isBoxed(Local variable) { 673 bool isBoxed(Local variable) {
664 return capturedVariables.containsKey(variable); 674 return capturedVariables.containsKey(variable);
665 } 675 }
666 676
667 void forEachCapturedVariable( 677 void forEachCapturedVariable(
668 f(LocalVariableElement variable, BoxFieldElement boxField)) { 678 f(LocalVariableElement variable, BoxFieldElement boxField)) {
669 capturedVariables.forEach(f); 679 capturedVariables.forEach(f);
670 } 680 }
671 681
672 // Should not be called. Added to make the new interface happy. 682 // Should not be called. Added to make the new interface happy.
673 bool variableIsUsedInTryOrSync(Local variable) => 683 bool localIsUsedInTryOrSync(Local variable) =>
674 throw new UnsupportedError("ClosureScopeImpl.variableIsUsedInTryOrSync"); 684 throw new UnsupportedError("ClosureScopeImpl.localIsUsedInTryOrSync");
675 685
676 // Should not be called. Added to make the new interface happy. 686 // Should not be called. Added to make the new interface happy.
677 Local get thisLocal => 687 Local get thisLocal =>
678 throw new UnsupportedError("ClosureScopeImpl.thisLocal"); 688 throw new UnsupportedError("ClosureScopeImpl.thisLocal");
679 689
680 String toString() { 690 String toString() {
681 String separator = ''; 691 String separator = '';
682 StringBuffer sb = new StringBuffer(); 692 StringBuffer sb = new StringBuffer();
683 sb.write('ClosureScopeImpl('); 693 sb.write('ClosureScopeImpl(');
684 if (boxElement != null) { 694 if (boxElement != null) {
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
734 /// Set of [variable]s referenced in this scope that are used inside a 744 /// Set of [variable]s referenced in this scope that are used inside a
735 /// `try` block or a `sync*` generator (this is important to know because 745 /// `try` block or a `sync*` generator (this is important to know because
736 /// boxing/redirection needs to happen for those local variables). 746 /// boxing/redirection needs to happen for those local variables).
737 /// 747 ///
738 /// Variables that are used in a try must be treated as boxed because the 748 /// Variables that are used in a try must be treated as boxed because the
739 /// control flow can be non-linear. 749 /// control flow can be non-linear.
740 /// 750 ///
741 /// Also parameters to a `sync*` generator must be boxed, because of the way 751 /// Also parameters to a `sync*` generator must be boxed, because of the way
742 /// we rewrite sync* functions. See also comments in [useLocal]. 752 /// we rewrite sync* functions. See also comments in [useLocal].
743 // TODO(johnniwinther): Add variables to this only if the variable is mutated. 753 // TODO(johnniwinther): Add variables to this only if the variable is mutated.
744 final Set<Local> variablesUsedInTryOrSync = new Set<Local>(); 754 final Set<Local> localsUsedInTryOrSync = new Set<Local>();
745 755
746 ClosureClassMap(this.closureEntity, this.closureClassEntity, this.callMethod, 756 ClosureClassMap(this.closureEntity, this.closureClassEntity, this.callMethod,
747 this.thisLocal); 757 this.thisLocal);
748 758
749 bool get hasBoxedVariables =>
750 throw new UnsupportedError("ClosureClassMap.hasBoxedVariables");
751
752 List<Local> get createdFieldEntities { 759 List<Local> get createdFieldEntities {
753 List<Local> fields = <Local>[]; 760 List<Local> fields = <Local>[];
754 if (closureClassEntity == null) return const <Local>[]; 761 if (closureClassEntity == null) return const <Local>[];
755 closureClassEntity.closureFields.forEach((field) { 762 closureClassEntity.closureFields.forEach((field) {
756 fields.add(field.local); 763 fields.add(field.local);
757 }); 764 });
758 return fields; 765 return fields;
759 } 766 }
760 767
761 void addFreeVariable(Local element) { 768 void addFreeVariable(Local element) {
762 assert(freeVariableMap[element] == null); 769 assert(freeVariableMap[element] == null);
763 freeVariableMap[element] = null; 770 freeVariableMap[element] = null;
764 } 771 }
765 772
766 Iterable<Local> get freeVariables => freeVariableMap.keys; 773 Iterable<Local> get freeVariables => freeVariableMap.keys;
767 774
768 bool isFreeVariable(Local element) { 775 bool isFreeVariable(Local element) {
769 return freeVariableMap.containsKey(element); 776 return freeVariableMap.containsKey(element);
770 } 777 }
771 778
772 void forEachFreeVariable(f(Local variable, FieldEntity field)) { 779 void forEachFreeVariable(f(Local variable, FieldEntity field)) {
773 freeVariableMap.forEach(f); 780 freeVariableMap.forEach(f);
774 } 781 }
775 782
776 FieldEntity get thisFieldEntity => freeVariableMap[thisLocal]; 783 FieldEntity get thisFieldEntity => freeVariableMap[thisLocal];
777 784
778 bool variableIsUsedInTryOrSync(Local variable) => 785 bool localIsUsedInTryOrSync(Local variable) =>
779 variablesUsedInTryOrSync.contains(variable); 786 localsUsedInTryOrSync.contains(variable);
780 787
781 Local getLocalVariableForClosureField(ClosureFieldElement field) { 788 Local getLocalVariableForClosureField(ClosureFieldElement field) {
782 return field.local; 789 return field.local;
783 } 790 }
784 791
785 bool get isClosure => closureEntity != null; 792 bool get isClosure => closureEntity != null;
786 793
787 bool capturingScopesBox(Local variable) { 794 bool capturingScopesBox(Local variable) {
788 return capturingScopes.values.any((scope) { 795 return capturingScopes.values.any((scope) {
789 return scope.boxedLoopVariables.contains(variable); 796 return scope.boxedLoopVariables.contains(variable);
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
1018 1025
1019 if (insideClosure && !inCurrentContext(variable)) { 1026 if (insideClosure && !inCurrentContext(variable)) {
1020 closureData.addFreeVariable(variable); 1027 closureData.addFreeVariable(variable);
1021 } else if (inTryStatement) { 1028 } else if (inTryStatement) {
1022 // Don't mark the this-element or a self-reference. This would complicate 1029 // Don't mark the this-element or a self-reference. This would complicate
1023 // things in the builder. 1030 // things in the builder.
1024 // Note that nested (named) functions are immutable. 1031 // Note that nested (named) functions are immutable.
1025 if (variable != closureData.thisLocal && 1032 if (variable != closureData.thisLocal &&
1026 variable != closureData.closureEntity && 1033 variable != closureData.closureEntity &&
1027 variable is! TypeVariableLocal) { 1034 variable is! TypeVariableLocal) {
1028 closureData.variablesUsedInTryOrSync.add(variable); 1035 closureData.localsUsedInTryOrSync.add(variable);
1029 } 1036 }
1030 } else if (variable is LocalParameterElement && 1037 } else if (variable is LocalParameterElement &&
1031 variable.functionDeclaration.asyncMarker == AsyncMarker.SYNC_STAR) { 1038 variable.functionDeclaration.asyncMarker == AsyncMarker.SYNC_STAR) {
1032 // Parameters in a sync* function are shared between each Iterator created 1039 // Parameters in a sync* function are shared between each Iterator created
1033 // by the Iterable returned by the function, therefore they must be boxed. 1040 // by the Iterable returned by the function, therefore they must be boxed.
1034 closureData.variablesUsedInTryOrSync.add(variable); 1041 closureData.localsUsedInTryOrSync.add(variable);
1035 } 1042 }
1036 } 1043 }
1037 1044
1038 void useTypeVariableAsLocal(ResolutionTypeVariableType typeVariable) { 1045 void useTypeVariableAsLocal(ResolutionTypeVariableType typeVariable) {
1039 useLocal(new TypeVariableLocal( 1046 useLocal(new TypeVariableLocal(
1040 typeVariable, outermostElement, outermostElement.memberContext)); 1047 typeVariable, outermostElement, outermostElement.memberContext));
1041 } 1048 }
1042 1049
1043 void declareLocal(LocalVariableElement element) { 1050 void declareLocal(LocalVariableElement element) {
1044 scopeVariables.add(element); 1051 scopeVariables.add(element);
(...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after
1525 /// 1532 ///
1526 /// Move the below classes to a JS model eventually. 1533 /// Move the below classes to a JS model eventually.
1527 /// 1534 ///
1528 abstract class JSEntity implements MemberEntity { 1535 abstract class JSEntity implements MemberEntity {
1529 Local get declaredEntity; 1536 Local get declaredEntity;
1530 } 1537 }
1531 1538
1532 abstract class PrivatelyNamedJSEntity implements JSEntity { 1539 abstract class PrivatelyNamedJSEntity implements JSEntity {
1533 Entity get rootOfScope; 1540 Entity get rootOfScope;
1534 } 1541 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_model/closure.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698