Chromium Code Reviews| 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 |