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

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

Issue 2995353002: Test the CapturedScope for local functions (Closed)
Patch Set: Created 3 years, 4 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) 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 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 /// generator (this is important to know because boxing/redirection needs to 81 /// generator (this is important to know because boxing/redirection needs to
82 /// happen for those local variables). 82 /// happen for those local variables).
83 /// 83 ///
84 /// Variables that are used in a try must be treated as boxed because the 84 /// Variables that are used in a try must be treated as boxed because the
85 /// control flow can be non-linear. 85 /// control flow can be non-linear.
86 /// 86 ///
87 /// Also parameters to a `sync*` generator must be boxed, because of the way 87 /// Also parameters to a `sync*` generator must be boxed, because of the way
88 /// we rewrite sync* functions. See also comments in 88 /// we rewrite sync* functions. See also comments in
89 /// [ClosureClassMap.useLocal]. 89 /// [ClosureClassMap.useLocal].
90 bool localIsUsedInTryOrSync(Local variable) => false; 90 bool localIsUsedInTryOrSync(Local variable) => false;
91
92 String toString() => 'ScopeInfo()';
91 } 93 }
92 94
93 /// Class representing the usage of a scope that has been captured in the 95 /// Class representing the usage of a scope that has been captured in the
94 /// context of a closure. 96 /// context of a closure.
95 class CapturedScope extends ScopeInfo { 97 class CapturedScope extends ScopeInfo {
96 const CapturedScope(); 98 const CapturedScope();
97 99
98 /// Loop through each variable that has been defined in this scope, modified 100 /// Loop through each variable that has been defined in this scope, modified
99 /// anywhere (this scope or another scope) and used in another scope. Because 101 /// anywhere (this scope or another scope) and used in another scope. Because
100 /// it is used in another scope, these variables need to be "boxed", creating 102 /// it is used in another scope, these variables need to be "boxed", creating
101 /// a thin wrapper around accesses to these variables so that accesses get 103 /// a thin wrapper around accesses to these variables so that accesses get
102 /// the correct updated value. The variables in localsUsedInTryOrSync may 104 /// the correct updated value. The variables in localsUsedInTryOrSync may
103 /// be included in this set. 105 /// be included in this set.
104 /// 106 ///
105 /// In the case of loops, this is the set of iteration variables (or any 107 /// In the case of loops, this is the set of iteration variables (or any
106 /// variables declared in the for loop expression (`for (...here...)`) that 108 /// variables declared in the for loop expression (`for (...here...)`) that
107 /// need to be boxed to snapshot their value. 109 /// need to be boxed to snapshot their value.
108 void forEachBoxedVariable(f(Local local, FieldEntity field)) {} 110 void forEachBoxedVariable(f(Local local, FieldEntity field)) {}
109 111
110 /// True if [variable] has been mutated and is also used in another scope. 112 /// True if [variable] has been mutated and is also used in another scope.
111 bool isBoxed(Local variable) => false; 113 bool isBoxed(Local variable) => false;
112 114
113 /// If true, this closure accesses a variable that was defined in an outside 115 /// If `true` this scope requires a `box`. A box is a JavaScript object that
114 /// scope and this variable gets modified at some point (sometimes we say that 116 /// holds all mutated variables declared in this scope that are accessed in
115 /// variable has been "captured"). In this situation, access to this variable 117 /// another scope.
116 /// is controlled via a wrapper (box) so that updates to this variable 118 bool get hasBox => false;
Emily Fortuna 2017/08/22 23:47:36 this naming of "context" was suggested by Siggi to
Johnni Winther 2017/08/23 07:47:17 [context] _is_ the box, i.e. the JS object that ho
117 /// are done in a way that is in line with Dart's closure rules.
118 bool get requiresContextBox => false;
119 119
120 /// Accessor to the local environment in which a particular closure node is 120 /// Accessor to the box created for this scope. If [hasBox] is `false`,
121 /// executed. This will encapsulate the value of any variables that have been 121 /// `null` is returned.
122 /// scoped into this context from outside. This is an accessor to the 122 ///
123 /// contextBox that [requiresContextBox] is testing is required. 123 /// The box is a JavaScript object that holds all mutated variables declared
124 Local get context => null; 124 /// in this scope that are accessed in another scope.
125 Local get box => null;
126
127 String toString() => 'CapturedScope()';
125 } 128 }
126 129
127 /// Class that describes the actual mechanics of how values of variables 130 /// Class that describes the actual mechanics of how values of variables
128 /// instantiated in a loop are captured inside closures in the loop body. 131 /// instantiated in a loop are captured inside closures in the loop body.
129 /// Unlike JS, the value of a declared loop iteration variable in any closure 132 /// Unlike JS, the value of a declared loop iteration variable in any closure
130 /// is captured/snapshotted inside at each iteration point, as if we created a 133 /// is captured/snapshotted inside at each iteration point, as if we created a
131 /// new local variable for that value inside the loop. For example, for the 134 /// new local variable for that value inside the loop. For example, for the
132 /// following loop: 135 /// following loop:
133 /// 136 ///
134 /// var lst = []; 137 /// var lst = [];
(...skipping 20 matching lines...) Expand all
155 /// run(f) => f(); 158 /// run(f) => f();
156 /// var a; 159 /// var a;
157 /// for (int i = 0; i < 3; i++) { 160 /// for (int i = 0; i < 3; i++) {
158 /// var b = 3; 161 /// var b = 3;
159 /// a = () => b = i; 162 /// a = () => b = i;
160 /// } 163 /// }
161 /// 164 ///
162 /// `i` would be a part of the boxedLoopVariables AND boxedVariables, but b 165 /// `i` would be a part of the boxedLoopVariables AND boxedVariables, but b
163 /// would only be a part of boxedVariables. 166 /// would only be a part of boxedVariables.
164 List<Local> get boxedLoopVariables => const <Local>[]; 167 List<Local> get boxedLoopVariables => const <Local>[];
168
169 String toString() => 'CapturedLoopScope()';
165 } 170 }
166 171
167 /// Class that describes the actual mechanics of how the converted, rewritten 172 /// Class that describes the actual mechanics of how the converted, rewritten
168 /// closure is implemented. For example, for the following closure (named foo 173 /// closure is implemented. For example, for the following closure (named foo
169 /// for convenience): 174 /// for convenience):
170 /// 175 ///
171 /// var foo = (x) => y + x; 176 /// var foo = (x) => y + x;
172 /// 177 ///
173 /// We would produce the following class to control access to these variables in 178 /// We would produce the following class to control access to these variables in
174 /// the following way (modulo naming of variables, assuming that y is modified 179 /// the following way (modulo naming of variables, assuming that y is modified
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 223
219 /// Convenience pointer to the field entity representation in the closure 224 /// Convenience pointer to the field entity representation in the closure
220 /// class of the element representing `this`. 225 /// class of the element representing `this`.
221 FieldEntity get thisFieldEntity => null; 226 FieldEntity get thisFieldEntity => null;
222 227
223 /// Loop through every variable that has been captured in this closure. This 228 /// Loop through every variable that has been captured in this closure. This
224 /// consists of all the free variables (variables captured *just* in this 229 /// consists of all the free variables (variables captured *just* in this
225 /// closure) and all variables captured in nested scopes that we may be 230 /// closure) and all variables captured in nested scopes that we may be
226 /// capturing as well. These nested scopes hold "boxes" to hold the executable 231 /// capturing as well. These nested scopes hold "boxes" to hold the executable
227 /// context for that scope. 232 /// context for that scope.
233 // TODO(johnniwinther,efortuna): Remove the need for this. It is now only
234 // used in inference.
228 void forEachCapturedVariable(f(Local from, FieldEntity to)) {} 235 void forEachCapturedVariable(f(Local from, FieldEntity to)) {}
229 236
230 /// Loop through each variable that has been boxed in this closure class. Only 237 /// Loop through each variable that has been boxed in this closure class. Only
231 /// captured variables that are mutated need to be "boxed" (which basically 238 /// captured variables that are mutated need to be "boxed" (which basically
232 /// puts a thin layer between updates and reads to this variable to ensure 239 /// puts a thin layer between updates and reads to this variable to ensure
233 /// that every place that accesses it gets the correct updated value). This 240 /// that every place that accesses it gets the correct updated value). This
234 /// includes looping over variables that were boxed from other scopes, not 241 /// includes looping over variables that were boxed from other scopes, not
235 /// strictly variables defined in this closure, unlike the behavior in 242 /// strictly variables defined in this closure, unlike the behavior in
236 /// the superclass ScopeInfo. 243 /// the superclass ScopeInfo.
244 // TODO(johnniwinther,efortuna): Remove the need for this. It is now only
245 // used in inference.
237 void forEachBoxedVariable(f(Local local, FieldEntity field)) {} 246 void forEachBoxedVariable(f(Local local, FieldEntity field)) {}
238 247
239 /// Loop through each free variable in this closure. Free variables are the 248 /// Loop through each free variable in this closure. Free variables are the
240 /// variables that have been captured *just* in this closure, not in nested 249 /// variables that have been captured *just* in this closure, not in nested
241 /// scopes. 250 /// scopes.
242 void forEachFreeVariable(f(Local variable, FieldEntity field)) {} 251 void forEachFreeVariable(f(Local variable, FieldEntity field)) {}
243 252
244 /// Return true if [variable] has been captured and mutated (all other 253 /// Return true if [variable] has been captured and mutated (all other
245 /// variables do not require boxing). 254 /// variables do not require boxing).
255 // TODO(johnniwinther,efortuna): Remove the need for this. It is now only
256 // used in inference.
246 bool isVariableBoxed(Local variable) => false; 257 bool isVariableBoxed(Local variable) => false;
247 258
248 // TODO(efortuna): Remove this method. The old system was using 259 // TODO(efortuna): Remove this method. The old system was using
249 // ClosureClassMaps for situations other than closure class maps, and that's 260 // ClosureClassMaps for situations other than closure class maps, and that's
250 // just confusing. 261 // just confusing.
251 bool get isClosure => false; 262 bool get isClosure => false;
252 } 263 }
253 264
254 class ClosureTask extends ClosureConversionTask<Node> { 265 class ClosureTask extends ClosureConversionTask<Node> {
255 Map<Node, CapturedScopeImpl> _closureInfoMap = <Node, CapturedScopeImpl>{}; 266 Map<Node, CapturedScopeImpl> _closureInfoMap = <Node, CapturedScopeImpl>{};
(...skipping 15 matching lines...) Expand all
271 createClosureClasses(closedWorldRefiner); 282 createClosureClasses(closedWorldRefiner);
272 } 283 }
273 284
274 CapturedScope _getCapturedScope(Node node) { 285 CapturedScope _getCapturedScope(Node node) {
275 var value = _closureInfoMap[node]; 286 var value = _closureInfoMap[node];
276 return value == null ? const CapturedScope() : value; 287 return value == null ? const CapturedScope() : value;
277 } 288 }
278 289
279 CapturedScope getCapturedScope(covariant MemberElement member) { 290 CapturedScope getCapturedScope(covariant MemberElement member) {
280 ResolvedAst resolvedAst = member.resolvedAst; 291 ResolvedAst resolvedAst = member.resolvedAst;
281 if (resolvedAst.kind != ResolvedAstKind.PARSED) 292 if (resolvedAst.kind != ResolvedAstKind.PARSED) {
282 return const CapturedScope(); 293 return const CapturedScope();
294 }
283 return _getCapturedScope(resolvedAst.node); 295 return _getCapturedScope(resolvedAst.node);
284 } 296 }
285 297
286 ScopeInfo getScopeInfo(MemberEntity member) { 298 ScopeInfo getScopeInfo(MemberEntity member) {
287 return _getMemberMapping(member); 299 return _getMemberMapping(member);
288 } 300 }
289 301
290 ClosureRepresentationInfo getClosureInfoForMember(MemberEntity member) { 302 ClosureRepresentationInfo getClosureInfoForMember(MemberEntity member) {
291 return _getMemberMapping(member); 303 return _getMemberMapping(member);
292 } 304 }
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after
682 final BoxLocal boxElement; 694 final BoxLocal boxElement;
683 final Map<Local, BoxFieldElement> capturedVariables; 695 final Map<Local, BoxFieldElement> capturedVariables;
684 696
685 // If the scope is attached to a [For] contains the variables that are 697 // If the scope is attached to a [For] contains the variables that are
686 // declared in the initializer of the [For] and that need to be boxed. 698 // declared in the initializer of the [For] and that need to be boxed.
687 // Otherwise contains the empty List. 699 // Otherwise contains the empty List.
688 List<Local> boxedLoopVariables = const <Local>[]; 700 List<Local> boxedLoopVariables = const <Local>[];
689 701
690 CapturedScopeImpl(this.boxElement, this.capturedVariables); 702 CapturedScopeImpl(this.boxElement, this.capturedVariables);
691 703
692 Local get context => boxElement; 704 Local get box => boxElement;
693 705
694 bool get requiresContextBox => capturedVariables.keys.isNotEmpty; 706 bool get hasBox => boxElement != null;
695 707
696 void forEachBoxedVariable(f(Local local, FieldEntity field)) { 708 void forEachBoxedVariable(f(Local local, FieldEntity field)) {
697 capturedVariables.forEach(f); 709 capturedVariables.forEach(f);
698 } 710 }
699 711
700 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; 712 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
701 713
702 bool isBoxed(Local variable) { 714 bool isBoxed(Local variable) {
703 return capturedVariables.containsKey(variable); 715 return capturedVariables.containsKey(variable);
704 } 716 }
(...skipping 851 matching lines...) Expand 10 before | Expand all | Expand 10 after
1556 /// 1568 ///
1557 /// Move the below classes to a JS model eventually. 1569 /// Move the below classes to a JS model eventually.
1558 /// 1570 ///
1559 abstract class JSEntity implements MemberEntity { 1571 abstract class JSEntity implements MemberEntity {
1560 Local get declaredEntity; 1572 Local get declaredEntity;
1561 } 1573 }
1562 1574
1563 abstract class PrivatelyNamedJSEntity implements JSEntity { 1575 abstract class PrivatelyNamedJSEntity implements JSEntity {
1564 Entity get rootOfScope; 1576 Entity get rootOfScope;
1565 } 1577 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_model/closure.dart » ('j') | pkg/compiler/lib/src/js_model/closure.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698