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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 45 // one for local functions. | 45 // one for local functions. |
| 46 ScopeInfo getScopeInfo(covariant Entity member); | 46 ScopeInfo getScopeInfo(covariant Entity member); |
| 47 | 47 |
| 48 /// This returns the same information as ScopeInfo, but can be called in | 48 /// This returns the same information as ScopeInfo, but can be called in |
| 49 /// situations when you are sure you are dealing with a closure specifically. | 49 /// situations when you are sure you are dealing with a closure specifically. |
| 50 ClosureRepresentationInfo getClosureRepresentationInfo( | 50 ClosureRepresentationInfo getClosureRepresentationInfo( |
| 51 covariant Entity member); | 51 covariant Entity member); |
| 52 | 52 |
| 53 /// Look up information about a loop, in case any variables it declares need | 53 /// Look up information about a loop, in case any variables it declares need |
| 54 /// to be boxed/snapshotted. | 54 /// to be boxed/snapshotted. |
| 55 LoopClosureRepresentationInfo getClosureRepresentationInfoForLoop(T loopNode); | 55 ClosureBase getClosureRepresentationInfoForLoop(T loopNode); |
| 56 | 56 |
| 57 /// Accessor to the information about closures that the SSA builder will use. | 57 /// Accessor to the information about closures that the SSA builder will use. |
| 58 ClosureAnalysisInfo getClosureAnalysisInfo(T node); | 58 ClosureBase getClosureBase(T node); |
| 59 } | 59 } |
| 60 | 60 |
| 61 /// Class that represents one level of scoping information, whether this scope | 61 /// Class that represents one level of scoping information, whether this scope |
| 62 /// is a closure or not. This is specifically used to store information | 62 /// is a closure or not. This is specifically used to store information |
| 63 /// about the usage of variables in try or sync blocks, because they need to be | 63 /// about the usage of variables in try or sync blocks, because they need to be |
| 64 /// boxed. | 64 /// boxed. |
| 65 /// | 65 /// |
| 66 /// Variables that are used in a try must be treated as boxed because the | 66 /// Variables that are used in a try must be treated as boxed because the |
| 67 /// control flow can be non-linear. Also parameters to a `sync*` generator must | 67 /// control flow can be non-linear. Also parameters to a `sync*` generator must |
| 68 /// be boxed, because of the way we rewrite sync* functions. See also comments | 68 /// be boxed, because of the way we rewrite sync* functions. See also comments |
| 69 /// in [ClosureClassMap.useLocal]. | 69 /// in [ClosureClassMap.useLocal]. |
| 70 class ScopeInfo { | 70 class ScopeInfo { |
| 71 const ScopeInfo(); | 71 const ScopeInfo(); |
| 72 | 72 |
| 73 /// Convenience reference pointer to the element representing `this`. | |
| 74 /// If this scope is not in an instance member, it will be null. | |
| 75 Local get thisLocal => null; | |
| 76 | |
| 73 /// 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*` |
| 74 /// generator (this is important to know because boxing/redirection needs to | 78 /// generator (this is important to know because boxing/redirection needs to |
| 75 /// happen for those local variables). | 79 /// happen for those local variables). |
| 76 /// | 80 /// |
| 77 /// 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 |
| 78 /// control flow can be non-linear. | 82 /// control flow can be non-linear. |
| 79 /// | 83 /// |
| 80 /// 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 |
| 81 /// we rewrite sync* functions. See also comments in | 85 /// we rewrite sync* functions. See also comments in |
| 82 /// [ClosureClassMap.useLocal]. | 86 /// [ClosureClassMap.useLocal]. |
| 83 bool variableIsUsedInTryOrSync(Local variable) => false; | 87 bool variableIsUsedInTryOrSync(Local variable) => false; |
| 84 | 88 |
| 85 /// Convenience reference pointer to the element representing `this`. | 89 /// Loop through each variabe that has been defined in this scope, modified |
|
Johnni Winther
2017/06/26 08:31:39
`variabe` -> `variable`
Emily Fortuna
2017/06/26 21:57:19
Done.
| |
| 86 /// If this scope is not in an instance member, it will be null. | 90 /// anywhere (this scope or another scope) and used in another scope . Because |
|
Johnni Winther
2017/06/26 08:31:39
`scope .` -> `scope.`
Start a new paragraph at`Be
Emily Fortuna
2017/06/26 21:57:20
Done.
| |
| 87 Local get thisLocal => null; | 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 | |
| 93 /// the correct updated value. The variables in variablesUsedInTryOrSync may | |
| 94 /// be included in this set. | |
| 95 /// | |
| 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 | |
| 98 /// need to be boxed to snapshot their value. | |
| 99 void forEachBoxedVariable(f(Local local, FieldEntity field)) {} | |
| 100 | |
| 101 /// True if [variable] has been mutated and is also used in another scope. | |
| 102 bool isBoxed(Local variable) => false; | |
| 103 | |
| 104 /// True if this loop declares any variables that need to be boxed. | |
|
Johnni Winther
2017/06/26 08:31:39
`this loop` -> `this scope`
Emily Fortuna
2017/06/26 21:57:20
thank you!
| |
| 105 bool get hasBoxedVariables => false; | |
| 88 } | 106 } |
| 89 | 107 |
| 90 /// Class that provides a black-box interface to information gleaned from | 108 /// Class that provides a basic interface for closures. Actual Dart closures |
| 91 /// analyzing a closure's characteristics, most commonly used to influence how | 109 /// will use this class (see [ClosureRepresentationInfo]) as well as loops. |
| 92 /// code should be generated in SSA builder stage. | 110 class ClosureBase extends ScopeInfo { |
| 93 class ClosureAnalysisInfo { | 111 const ClosureBase(); |
| 94 const ClosureAnalysisInfo(); | |
| 95 | 112 |
| 96 /// If true, this closure accesses a variable that was defined in an outside | 113 /// If true, this closure accesses a variable that was defined in an outside |
| 97 /// scope and this variable gets modified at some point (sometimes we say that | 114 /// scope and this variable gets modified at some point (sometimes we say that |
| 98 /// variable has been "captured"). In this situation, access to this variable | 115 /// variable has been "captured"). In this situation, access to this variable |
| 99 /// is controlled via a wrapper (box) so that updates to this variable | 116 /// is controlled via a wrapper (box) so that updates to this variable |
| 100 /// are done in a way that is in line with Dart's closure rules. | 117 /// are done in a way that is in line with Dart's closure rules. |
| 101 bool get requiresContextBox => false; | 118 bool get requiresContextBox => false; |
| 102 | 119 |
| 103 /// Accessor to the local environment in which a particular closure node is | 120 /// Accessor to the local environment in which a particular closure node is |
| 104 /// executed. This will encapsulate the value of any variables that have been | 121 /// executed. This will encapsulate the value of any variables that have been |
| 105 /// scoped into this context from outside. This is an accessor to the | 122 /// scoped into this context from outside. This is an accessor to the |
| 106 /// contextBox that [requiresContextBox] is testing is required. | 123 /// contextBox that [requiresContextBox] is testing is required. |
| 107 Local get context => null; | 124 Local get context => null; |
| 108 | |
| 109 /// True if the specified variable has been mutated inside the scope of this | |
| 110 /// closure. | |
| 111 bool isCaptured(Local variable) => false; | |
| 112 | |
| 113 /// Loop through every variable that has been captured in this closure. This | |
| 114 /// consists of all the free variables (variables captured *just* in this | |
| 115 /// closure) and all variables captured in nested scopes that we may be | |
| 116 /// capturing as well. | |
| 117 void forEachCapturedVariable(f(Local from, FieldEntity to)) {} | |
| 118 } | |
| 119 | |
| 120 /// Class that describes the actual mechanics of how a loop is | |
| 121 /// converted/rewritten without closures. Unlike JS, the value of a declared | |
| 122 /// loop iteration variable in any closure is captured/snapshotted inside at | |
| 123 /// each iteration point, as if we created a new local variable for that value | |
| 124 /// inside the loop. For example, for the following loop: | |
| 125 /// | |
| 126 /// var lst = []; | |
| 127 /// for (int i = 0; i < 5; i++) lst.add(()=>i); | |
| 128 /// var result = list.map((f) => f()).toList(); | |
| 129 /// | |
| 130 /// `result` will be [0, 1, 2, 3, 4], whereas were this JS code | |
| 131 /// the result would be [5, 5, 5, 5, 5]. Because of this difference we need to | |
| 132 /// create a closure for these sorts of loops to capture the variable's value at | |
| 133 /// each iteration, by boxing the iteration variable[s]. | |
| 134 class LoopClosureRepresentationInfo extends ClosureAnalysisInfo { | |
| 135 const LoopClosureRepresentationInfo(); | |
| 136 | |
| 137 /// True if this loop declares any variables that need to be boxed. | |
| 138 bool get hasBoxedVariables => false; | |
| 139 | |
| 140 /// The set of iteration variables (or variables declared in the for loop | |
| 141 /// expression (`for (...here...)`) that need to be boxed to snapshot their | |
| 142 /// value. | |
| 143 List<Local> get boxedVariables => const <Local>[]; | |
| 144 } | 125 } |
| 145 | 126 |
| 146 /// Class that describes the actual mechanics of how the converted, rewritten | 127 /// Class that describes the actual mechanics of how the converted, rewritten |
| 147 /// closure is implemented. For example, for the following closure (named foo | 128 /// closure is implemented. For example, for the following closure (named foo |
| 148 /// for convenience): | 129 /// for convenience): |
| 149 /// | 130 /// |
| 150 /// var foo = (x) => y + x; | 131 /// var foo = (x) => y + x; |
| 151 /// | 132 /// |
| 152 /// We would produce the following class to control access to these variables in | 133 /// 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 | 134 /// the following way (modulo naming of variables, assuming that y is modified |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 202 /// Loop through every variable that has been captured in this closure. This | 183 /// Loop through every variable that has been captured in this closure. This |
| 203 /// consists of all the free variables (variables captured *just* in this | 184 /// consists of all the free variables (variables captured *just* in this |
| 204 /// closure) and all variables captured in nested scopes that we may be | 185 /// closure) and all variables captured in nested scopes that we may be |
| 205 /// capturing as well. These nested scopes hold "boxes" to hold the executable | 186 /// capturing as well. These nested scopes hold "boxes" to hold the executable |
| 206 /// context for that scope. | 187 /// context for that scope. |
| 207 void forEachCapturedVariable(f(Local from, FieldEntity to)) {} | 188 void forEachCapturedVariable(f(Local from, FieldEntity to)) {} |
| 208 | 189 |
| 209 /// Loop through each variable that has been boxed in this closure class. Only | 190 /// Loop through each variable that has been boxed in this closure class. Only |
| 210 /// captured variables that are mutated need to be "boxed" (which basically | 191 /// captured variables that are mutated need to be "boxed" (which basically |
| 211 /// puts a thin layer between updates and reads to this variable to ensure | 192 /// puts a thin layer between updates and reads to this variable to ensure |
| 212 /// that every place that accesses it gets the correct updated value). | 193 /// that every place that accesses it gets the correct updated value). This |
| 194 /// includes looping over variables that were boxed from other scopes, not | |
| 195 /// strictly variables defined in this closure, unlike the behavior in | |
| 196 /// the superclass ScopeInfo. | |
| 197 @override | |
| 213 void forEachBoxedVariable(f(Local local, FieldEntity field)) {} | 198 void forEachBoxedVariable(f(Local local, FieldEntity field)) {} |
| 214 | 199 |
| 215 /// Loop through each free variable in this closure. Free variables are the | 200 /// Loop through each free variable in this closure. Free variables are the |
| 216 /// variables that have been captured *just* in this closure, not in nested | 201 /// variables that have been captured *just* in this closure, not in nested |
| 217 /// scopes. | 202 /// scopes. |
| 218 void forEachFreeVariable(f(Local variable, FieldEntity field)) {} | 203 void forEachFreeVariable(f(Local variable, FieldEntity field)) {} |
| 219 | 204 |
| 220 /// Return true if [variable] has been captured and mutated (all other | 205 /// Return true if [variable] has been captured and mutated (all other |
| 221 /// variables do not require boxing). | 206 /// variables do not require boxing). |
| 222 bool isVariableBoxed(Local variable) => false; | 207 bool isVariableBoxed(Local variable) => false; |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 238 | 223 |
| 239 String get name => "Closure Simplifier"; | 224 String get name => "Closure Simplifier"; |
| 240 | 225 |
| 241 DiagnosticReporter get reporter => compiler.reporter; | 226 DiagnosticReporter get reporter => compiler.reporter; |
| 242 | 227 |
| 243 void convertClosures(Iterable<MemberEntity> processedEntities, | 228 void convertClosures(Iterable<MemberEntity> processedEntities, |
| 244 ClosedWorldRefiner closedWorldRefiner) { | 229 ClosedWorldRefiner closedWorldRefiner) { |
| 245 createClosureClasses(closedWorldRefiner); | 230 createClosureClasses(closedWorldRefiner); |
| 246 } | 231 } |
| 247 | 232 |
| 248 ClosureAnalysisInfo getClosureAnalysisInfo(Node node) { | 233 ClosureBase getClosureBase(Node node) { |
| 249 var value = _closureInfoMap[node]; | 234 var value = _closureInfoMap[node]; |
| 250 return value == null ? const ClosureAnalysisInfo() : value; | 235 return value == null ? const ClosureBase() : value; |
| 251 } | 236 } |
| 252 | 237 |
| 253 ScopeInfo getScopeInfo(Element member) { | 238 ScopeInfo getScopeInfo(Element member) { |
| 254 return getClosureToClassMapping(member); | 239 return getClosureToClassMapping(member); |
| 255 } | 240 } |
| 256 | 241 |
| 257 ClosureRepresentationInfo getClosureRepresentationInfo(Element member) { | 242 ClosureRepresentationInfo getClosureRepresentationInfo(Element member) { |
| 258 return getClosureToClassMapping(member); | 243 return getClosureToClassMapping(member); |
| 259 } | 244 } |
| 260 | 245 |
| 261 LoopClosureRepresentationInfo getClosureRepresentationInfoForLoop( | 246 ClosureBase getClosureRepresentationInfoForLoop(Node loopNode) { |
| 262 Node loopNode) { | |
| 263 var value = _closureInfoMap[loopNode]; | 247 var value = _closureInfoMap[loopNode]; |
| 264 return value == null ? const LoopClosureRepresentationInfo() : value; | 248 return value == null ? const ClosureBase() : value; |
| 265 } | 249 } |
| 266 | 250 |
| 267 /// Returns the [ClosureClassMap] computed for [resolvedAst]. | 251 /// Returns the [ClosureClassMap] computed for [resolvedAst]. |
| 268 ClosureClassMap getClosureToClassMapping(Element element) { | 252 ClosureClassMap getClosureToClassMapping(Element element) { |
| 269 return measure(() { | 253 return measure(() { |
| 270 if (element.isGenerativeConstructorBody) { | 254 if (element.isGenerativeConstructorBody) { |
| 271 ConstructorBodyElement constructorBody = element; | 255 ConstructorBodyElement constructorBody = element; |
| 272 element = constructorBody.constructor; | 256 element = constructorBody.constructor; |
| 273 } | 257 } |
| 274 ClosureClassMap closureClassMap = _closureMappingCache[element]; | 258 ClosureClassMap closureClassMap = _closureMappingCache[element]; |
| (...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 622 expression.compilationUnit.script.resourceUri); | 606 expression.compilationUnit.script.resourceUri); |
| 623 } | 607 } |
| 624 | 608 |
| 625 accept(ElementVisitor visitor, arg) { | 609 accept(ElementVisitor visitor, arg) { |
| 626 return visitor.visitMethodElement(this, arg); | 610 return visitor.visitMethodElement(this, arg); |
| 627 } | 611 } |
| 628 } | 612 } |
| 629 | 613 |
| 630 // The box-element for a scope, and the captured variables that need to be | 614 // The box-element for a scope, and the captured variables that need to be |
| 631 // stored in the box. | 615 // stored in the box. |
| 632 class ClosureScope | 616 class ClosureScope implements ClosureBase { |
|
Siggi Cherem (dart-lang)
2017/06/26 16:54:42
mmm... I sort of like the idea of swapping the two
| |
| 633 implements ClosureAnalysisInfo, LoopClosureRepresentationInfo { | |
| 634 final BoxLocal boxElement; | 617 final BoxLocal boxElement; |
| 635 final Map<Local, BoxFieldElement> capturedVariables; | 618 final Map<Local, BoxFieldElement> capturedVariables; |
| 636 | 619 |
| 637 // If the scope is attached to a [For] contains the variables that are | 620 // If the scope is attached to a [For] contains the variables that are |
| 638 // declared in the initializer of the [For] and that need to be boxed. | 621 // declared in the initializer of the [For] and that need to be boxed. |
| 639 // Otherwise contains the empty List. | 622 // Otherwise contains the empty List. |
| 640 List<Local> boxedLoopVariables = const <Local>[]; | 623 List<Local> boxedLoopVariables = const <Local>[]; |
| 641 | 624 |
| 642 ClosureScope(this.boxElement, this.capturedVariables); | 625 ClosureScope(this.boxElement, this.capturedVariables); |
| 643 | 626 |
| 644 Local get context => boxElement; | 627 Local get context => boxElement; |
| 645 | 628 |
| 646 bool get requiresContextBox => capturedVariables.keys.isNotEmpty; | 629 bool get requiresContextBox => capturedVariables.keys.isNotEmpty; |
| 647 | 630 |
| 648 List<Local> get boxedVariables => boxedLoopVariables; | 631 void forEachBoxedVariable(f(Local local, FieldEntity field)) { |
| 632 if (capturedVariables.isNotEmpty) { | |
| 633 capturedVariables.forEach(f); | |
|
Johnni Winther
2017/06/26 08:31:39
assert(boxedLoopVariables.isEmpty)
| |
| 634 } else { | |
| 635 for (Local l in boxedLoopVariables) { | |
| 636 // The boxes for loop variables are constructed on-demand per-iteration | |
| 637 // in the locals handler. | |
| 638 f(l, null); | |
| 639 } | |
| 640 } | |
| 641 } | |
| 649 | 642 |
| 650 bool get hasBoxedVariables => !boxedLoopVariables.isEmpty; | 643 Map<Local, BoxFieldElement> get boxedVariables { |
|
Johnni Winther
2017/06/26 08:31:39
When is this used?
Emily Fortuna
2017/06/26 21:57:20
oops. that was holdover from a previous edit. Remo
| |
| 644 Map<Local, BoxFieldElement> temp = <Local, BoxFieldElement>{}; | |
| 645 boxedLoopVariables.forEach((Local l) { | |
| 646 temp[l] = null; | |
| 647 }); | |
| 648 return capturedVariables.isNotEmpty ? capturedVariables : temp; | |
| 649 } | |
| 651 | 650 |
| 652 bool isCaptured(Local variable) { | 651 bool get hasBoxedVariables => !capturedVariables.isEmpty; |
| 652 | |
| 653 bool isBoxed(Local variable) { | |
| 653 return capturedVariables.containsKey(variable); | 654 return capturedVariables.containsKey(variable); |
| 654 } | 655 } |
| 655 | 656 |
| 656 void forEachCapturedVariable( | 657 void forEachCapturedVariable( |
| 657 f(LocalVariableElement variable, BoxFieldElement boxField)) { | 658 f(LocalVariableElement variable, BoxFieldElement boxField)) { |
| 658 capturedVariables.forEach(f); | 659 capturedVariables.forEach(f); |
| 659 } | 660 } |
| 660 | 661 |
| 662 // Should not be called. Added to make the new interface happy. | |
| 663 bool variableIsUsedInTryOrSync(Local variable) => | |
| 664 throw new UnsupportedError("ClosureScope.variableIsUsedInTryOrSync"); | |
| 665 | |
| 666 // Should not be called. Added to make the new interface happy. | |
| 667 Local get thisLocal => throw new UnsupportedError("ClosureScope.thisLocal"); | |
| 668 | |
| 661 String toString() { | 669 String toString() { |
| 662 String separator = ''; | 670 String separator = ''; |
| 663 StringBuffer sb = new StringBuffer(); | 671 StringBuffer sb = new StringBuffer(); |
| 664 sb.write('ClosureScope('); | 672 sb.write('ClosureScope('); |
| 665 if (boxElement != null) { | 673 if (boxElement != null) { |
| 666 sb.write('box=$boxElement'); | 674 sb.write('box=$boxElement'); |
| 667 separator = ','; | 675 separator = ','; |
| 668 } | 676 } |
| 669 if (boxedLoopVariables.isNotEmpty) { | 677 if (boxedLoopVariables.isNotEmpty) { |
| 670 sb.write(separator); | 678 sb.write(separator); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 719 /// control flow can be non-linear. | 727 /// control flow can be non-linear. |
| 720 /// | 728 /// |
| 721 /// Also parameters to a `sync*` generator must be boxed, because of the way | 729 /// Also parameters to a `sync*` generator must be boxed, because of the way |
| 722 /// we rewrite sync* functions. See also comments in [useLocal]. | 730 /// we rewrite sync* functions. See also comments in [useLocal]. |
| 723 // TODO(johnniwinther): Add variables to this only if the variable is mutated. | 731 // TODO(johnniwinther): Add variables to this only if the variable is mutated. |
| 724 final Set<Local> variablesUsedInTryOrSync = new Set<Local>(); | 732 final Set<Local> variablesUsedInTryOrSync = new Set<Local>(); |
| 725 | 733 |
| 726 ClosureClassMap(this.closureEntity, this.closureClassEntity, this.callMethod, | 734 ClosureClassMap(this.closureEntity, this.closureClassEntity, this.callMethod, |
| 727 this.thisLocal); | 735 this.thisLocal); |
| 728 | 736 |
| 737 bool get hasBoxedVariables => | |
| 738 throw new UnsupportedError("ClosureClassMap.hasBoxedVariables"); | |
| 739 | |
| 729 List<Local> get createdFieldEntities { | 740 List<Local> get createdFieldEntities { |
| 730 List<Local> fields = <Local>[]; | 741 List<Local> fields = <Local>[]; |
| 731 if (closureClassEntity == null) return const <Local>[]; | 742 if (closureClassEntity == null) return const <Local>[]; |
| 732 closureClassEntity.closureFields.forEach((field) { | 743 closureClassEntity.closureFields.forEach((field) { |
| 733 fields.add(field.local); | 744 fields.add(field.local); |
| 734 }); | 745 }); |
| 735 return fields; | 746 return fields; |
| 736 } | 747 } |
| 737 | 748 |
| 738 void addFreeVariable(Local element) { | 749 void addFreeVariable(Local element) { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 788 void forEachBoxedVariable( | 799 void forEachBoxedVariable( |
| 789 void f(LocalVariableElement local, BoxFieldElement field)) { | 800 void f(LocalVariableElement local, BoxFieldElement field)) { |
| 790 freeVariableMap.forEach((variable, copy) { | 801 freeVariableMap.forEach((variable, copy) { |
| 791 if (!isVariableBoxed(variable)) return; | 802 if (!isVariableBoxed(variable)) return; |
| 792 f(variable, copy); | 803 f(variable, copy); |
| 793 }); | 804 }); |
| 794 capturingScopes.values.forEach((ClosureScope scope) { | 805 capturingScopes.values.forEach((ClosureScope scope) { |
| 795 scope.forEachCapturedVariable(f); | 806 scope.forEachCapturedVariable(f); |
| 796 }); | 807 }); |
| 797 } | 808 } |
| 809 | |
| 810 bool isBoxed(Local local) { | |
| 811 bool variableIsBoxed = false; | |
| 812 forEachBoxedVariable((LocalVariableElement element, BoxFieldElement field) { | |
| 813 if (element == local) variableIsBoxed = true; | |
| 814 }); | |
| 815 return variableIsBoxed; | |
| 816 } | |
| 798 } | 817 } |
| 799 | 818 |
| 800 class ClosureTranslator extends Visitor { | 819 class ClosureTranslator extends Visitor { |
| 801 final Compiler compiler; | 820 final Compiler compiler; |
| 802 final ClosedWorldRefiner closedWorldRefiner; | 821 final ClosedWorldRefiner closedWorldRefiner; |
| 803 final TreeElements elements; | 822 final TreeElements elements; |
| 804 int closureFieldCounter = 0; | 823 int closureFieldCounter = 0; |
| 805 int boxedFieldCounter = 0; | 824 int boxedFieldCounter = 0; |
| 806 bool inTryStatement = false; | 825 bool inTryStatement = false; |
| 807 | 826 |
| (...skipping 685 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1493 /// | 1512 /// |
| 1494 /// Move the below classes to a JS model eventually. | 1513 /// Move the below classes to a JS model eventually. |
| 1495 /// | 1514 /// |
| 1496 abstract class JSEntity implements MemberEntity { | 1515 abstract class JSEntity implements MemberEntity { |
| 1497 Local get declaredEntity; | 1516 Local get declaredEntity; |
| 1498 } | 1517 } |
| 1499 | 1518 |
| 1500 abstract class PrivatelyNamedJSEntity implements JSEntity { | 1519 abstract class PrivatelyNamedJSEntity implements JSEntity { |
| 1501 Entity get rootOfScope; | 1520 Entity get rootOfScope; |
| 1502 } | 1521 } |
| OLD | NEW |