OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |