| 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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 46 // one for local functions. | 46 // one for local functions. |
| 47 ScopeInfo getScopeInfo(covariant Entity member); | 47 ScopeInfo getScopeInfo(covariant Entity member); |
| 48 | 48 |
| 49 /// This returns the same information as ScopeInfo, but can be called in | 49 /// This returns the same information as ScopeInfo, but can be called in |
| 50 /// situations when you are sure you are dealing with a closure specifically. | 50 /// situations when you are sure you are dealing with a closure specifically. |
| 51 ClosureRepresentationInfo getClosureRepresentationInfo( | 51 ClosureRepresentationInfo getClosureRepresentationInfo( |
| 52 covariant Entity member); | 52 covariant Entity member); |
| 53 | 53 |
| 54 /// Look up information about a loop, in case any variables it declares need | 54 /// Look up information about a loop, in case any variables it declares need |
| 55 /// to be boxed/snapshotted. | 55 /// to be boxed/snapshotted. |
| 56 LoopClosureScope getLoopClosureScope(T loopNode); | 56 CapturedLoopScope getCapturedLoopScope(T loopNode); |
| 57 | 57 |
| 58 /// Accessor to the information about closures that the SSA builder will use. | 58 /// Accessor to the information about scopes that closures capture. Used by |
| 59 ClosureScope getClosureScope(MemberEntity entity); | 59 /// the SSA builder. |
| 60 CapturedScope getCapturedScope(MemberEntity entity); |
| 60 } | 61 } |
| 61 | 62 |
| 62 /// Class that represents one level of scoping information, whether this scope | 63 /// Class that represents one level of scoping information, whether this scope |
| 63 /// is a closure or not. This is specifically used to store information | 64 /// is a closure or not. This is specifically used to store information |
| 64 /// about the usage of variables in try or sync blocks, because they need to be | 65 /// about the usage of variables in try or sync blocks, because they need to be |
| 65 /// boxed. | 66 /// boxed. |
| 66 /// | 67 /// |
| 67 /// Variables that are used in a try must be treated as boxed because the | 68 /// Variables that are used in a try must be treated as boxed because the |
| 68 /// control flow can be non-linear. Also parameters to a `sync*` generator must | 69 /// control flow can be non-linear. Also parameters to a `sync*` generator must |
| 69 /// be boxed, because of the way we rewrite sync* functions. See also comments | 70 /// be boxed, because of the way we rewrite sync* functions. See also comments |
| (...skipping 28 matching lines...) Expand all Loading... |
| 98 /// variables declared in the for loop expression (`for (...here...)`) that | 99 /// variables declared in the for loop expression (`for (...here...)`) that |
| 99 /// need to be boxed to snapshot their value. | 100 /// need to be boxed to snapshot their value. |
| 100 void forEachBoxedVariable(f(Local local, FieldEntity field)) {} | 101 void forEachBoxedVariable(f(Local local, FieldEntity field)) {} |
| 101 | 102 |
| 102 /// True if [variable] has been mutated and is also used in another scope. | 103 /// True if [variable] has been mutated and is also used in another scope. |
| 103 bool isBoxed(Local variable) => false; | 104 bool isBoxed(Local variable) => false; |
| 104 } | 105 } |
| 105 | 106 |
| 106 /// Class representing the usage of a scope that has been captured in the | 107 /// Class representing the usage of a scope that has been captured in the |
| 107 /// context of a closure. | 108 /// context of a closure. |
| 108 class ClosureScope extends ScopeInfo { | 109 class CapturedScope extends ScopeInfo { |
| 109 const ClosureScope(); | 110 const CapturedScope(); |
| 110 | 111 |
| 111 /// If true, this closure accesses a variable that was defined in an outside | 112 /// If true, this closure accesses a variable that was defined in an outside |
| 112 /// scope and this variable gets modified at some point (sometimes we say that | 113 /// scope and this variable gets modified at some point (sometimes we say that |
| 113 /// variable has been "captured"). In this situation, access to this variable | 114 /// variable has been "captured"). In this situation, access to this variable |
| 114 /// is controlled via a wrapper (box) so that updates to this variable | 115 /// is controlled via a wrapper (box) so that updates to this variable |
| 115 /// are done in a way that is in line with Dart's closure rules. | 116 /// are done in a way that is in line with Dart's closure rules. |
| 116 bool get requiresContextBox => false; | 117 bool get requiresContextBox => false; |
| 117 | 118 |
| 118 /// Accessor to the local environment in which a particular closure node is | 119 /// Accessor to the local environment in which a particular closure node is |
| 119 /// executed. This will encapsulate the value of any variables that have been | 120 /// executed. This will encapsulate the value of any variables that have been |
| (...skipping 10 matching lines...) Expand all Loading... |
| 130 /// following loop: | 131 /// following loop: |
| 131 /// | 132 /// |
| 132 /// var lst = []; | 133 /// var lst = []; |
| 133 /// for (int i = 0; i < 5; i++) lst.add(()=>i); | 134 /// for (int i = 0; i < 5; i++) lst.add(()=>i); |
| 134 /// var result = list.map((f) => f()).toList(); | 135 /// var result = list.map((f) => f()).toList(); |
| 135 /// | 136 /// |
| 136 /// `result` will be [0, 1, 2, 3, 4], whereas were this JS code | 137 /// `result` will be [0, 1, 2, 3, 4], whereas were this JS code |
| 137 /// the result would be [5, 5, 5, 5, 5]. Because of this difference we need to | 138 /// the result would be [5, 5, 5, 5, 5]. Because of this difference we need to |
| 138 /// create a closure for these sorts of loops to capture the variable's value at | 139 /// create a closure for these sorts of loops to capture the variable's value at |
| 139 /// each iteration, by boxing the iteration variable[s]. | 140 /// each iteration, by boxing the iteration variable[s]. |
| 140 class LoopClosureScope extends ClosureScope { | 141 class CapturedLoopScope extends CapturedScope { |
| 141 const LoopClosureScope(); | 142 const CapturedLoopScope(); |
| 142 | 143 |
| 143 /// True if this loop scope declares in the first part of the loop | 144 /// True if this loop scope declares in the first part of the loop |
| 144 /// `for (<here>;...;...)` any variables that need to be boxed. | 145 /// `for (<here>;...;...)` any variables that need to be boxed. |
| 145 bool get hasBoxedLoopVariables => false; | 146 bool get hasBoxedLoopVariables => false; |
| 146 | 147 |
| 147 /// The set of iteration variables (or variables declared in the for loop | 148 /// The set of iteration variables (or variables declared in the for loop |
| 148 /// expression (`for (<here>; ... ; ...)`) that need to be boxed to snapshot | 149 /// expression (`for (<here>; ... ; ...)`) that need to be boxed to snapshot |
| 149 /// their value. These variables are also included in the set of | 150 /// their value. These variables are also included in the set of |
| 150 /// `forEachBoxedVariable` method. The distinction between these two sets is | 151 /// `forEachBoxedVariable` method. The distinction between these two sets is |
| 151 /// in this example: | 152 /// in this example: |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 244 /// variables do not require boxing). | 245 /// variables do not require boxing). |
| 245 bool isVariableBoxed(Local variable) => false; | 246 bool isVariableBoxed(Local variable) => false; |
| 246 | 247 |
| 247 // TODO(efortuna): Remove this method. The old system was using | 248 // TODO(efortuna): Remove this method. The old system was using |
| 248 // ClosureClassMaps for situations other than closure class maps, and that's | 249 // ClosureClassMaps for situations other than closure class maps, and that's |
| 249 // just confusing. | 250 // just confusing. |
| 250 bool get isClosure => false; | 251 bool get isClosure => false; |
| 251 } | 252 } |
| 252 | 253 |
| 253 class ClosureTask extends ClosureConversionTask<Node> { | 254 class ClosureTask extends ClosureConversionTask<Node> { |
| 254 Map<Node, ClosureScopeImpl> _closureInfoMap = <Node, ClosureScopeImpl>{}; | 255 Map<Node, CapturedScopeImpl> _closureInfoMap = <Node, CapturedScopeImpl>{}; |
| 255 Map<Element, ClosureClassMap> _closureMappingCache = | 256 Map<Element, ClosureClassMap> _closureMappingCache = |
| 256 <Element, ClosureClassMap>{}; | 257 <Element, ClosureClassMap>{}; |
| 257 Compiler compiler; | 258 Compiler compiler; |
| 258 ClosureTask(Compiler compiler) | 259 ClosureTask(Compiler compiler) |
| 259 : compiler = compiler, | 260 : compiler = compiler, |
| 260 super(compiler.measurer); | 261 super(compiler.measurer); |
| 261 | 262 |
| 262 String get name => "Closure Simplifier"; | 263 String get name => "Closure Simplifier"; |
| 263 | 264 |
| 264 DiagnosticReporter get reporter => compiler.reporter; | 265 DiagnosticReporter get reporter => compiler.reporter; |
| 265 | 266 |
| 266 void convertClosures(Iterable<MemberEntity> processedEntities, | 267 void convertClosures(Iterable<MemberEntity> processedEntities, |
| 267 ClosedWorldRefiner closedWorldRefiner) { | 268 ClosedWorldRefiner closedWorldRefiner) { |
| 268 createClosureClasses(closedWorldRefiner); | 269 createClosureClasses(closedWorldRefiner); |
| 269 } | 270 } |
| 270 | 271 |
| 271 ClosureScope _getClosureScope(Node node) { | 272 CapturedScope _getCapturedScope(Node node) { |
| 272 var value = _closureInfoMap[node]; | 273 var value = _closureInfoMap[node]; |
| 273 return value == null ? const ClosureScope() : value; | 274 return value == null ? const CapturedScope() : value; |
| 274 } | 275 } |
| 275 | 276 |
| 276 ClosureScope getClosureScope(covariant MemberElement member) { | 277 CapturedScope getCapturedScope(covariant MemberElement member) { |
| 277 ResolvedAst resolvedAst = member.resolvedAst; | 278 ResolvedAst resolvedAst = member.resolvedAst; |
| 278 if (resolvedAst.kind != ResolvedAstKind.PARSED) return const ClosureScope(); | 279 if (resolvedAst.kind != ResolvedAstKind.PARSED) |
| 279 return _getClosureScope(resolvedAst.node); | 280 return const CapturedScope(); |
| 281 return _getCapturedScope(resolvedAst.node); |
| 280 } | 282 } |
| 281 | 283 |
| 282 ScopeInfo getScopeInfo(Element member) { | 284 ScopeInfo getScopeInfo(Element member) { |
| 283 return getClosureToClassMapping(member); | 285 return getClosureToClassMapping(member); |
| 284 } | 286 } |
| 285 | 287 |
| 286 ClosureRepresentationInfo getClosureRepresentationInfo(Element member) { | 288 ClosureRepresentationInfo getClosureRepresentationInfo(Element member) { |
| 287 return getClosureToClassMapping(member); | 289 return getClosureToClassMapping(member); |
| 288 } | 290 } |
| 289 | 291 |
| 290 LoopClosureScope getLoopClosureScope(Node loopNode) { | 292 CapturedLoopScope getCapturedLoopScope(Node loopNode) { |
| 291 var value = _closureInfoMap[loopNode]; | 293 var value = _closureInfoMap[loopNode]; |
| 292 return value == null ? const LoopClosureScope() : value; | 294 return value == null ? const CapturedLoopScope() : value; |
| 293 } | 295 } |
| 294 | 296 |
| 295 /// Returns the [ClosureClassMap] computed for [resolvedAst]. | 297 /// Returns the [ClosureClassMap] computed for [resolvedAst]. |
| 296 ClosureClassMap getClosureToClassMapping(Element element) { | 298 ClosureClassMap getClosureToClassMapping(Element element) { |
| 297 return measure(() { | 299 return measure(() { |
| 298 if (element.isGenerativeConstructorBody) { | 300 if (element.isGenerativeConstructorBody) { |
| 299 ConstructorBodyElement constructorBody = element; | 301 ConstructorBodyElement constructorBody = element; |
| 300 element = constructorBody.constructor; | 302 element = constructorBody.constructor; |
| 301 } | 303 } |
| 302 ClosureClassMap closureClassMap = _closureMappingCache[element]; | 304 ClosureClassMap closureClassMap = _closureMappingCache[element]; |
| (...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 648 expression.compilationUnit.script.resourceUri); | 650 expression.compilationUnit.script.resourceUri); |
| 649 } | 651 } |
| 650 | 652 |
| 651 accept(ElementVisitor visitor, arg) { | 653 accept(ElementVisitor visitor, arg) { |
| 652 return visitor.visitMethodElement(this, arg); | 654 return visitor.visitMethodElement(this, arg); |
| 653 } | 655 } |
| 654 } | 656 } |
| 655 | 657 |
| 656 // The box-element for a scope, and the captured variables that need to be | 658 // The box-element for a scope, and the captured variables that need to be |
| 657 // stored in the box. | 659 // stored in the box. |
| 658 class ClosureScopeImpl implements ClosureScope, LoopClosureScope { | 660 class CapturedScopeImpl implements CapturedScope, CapturedLoopScope { |
| 659 final BoxLocal boxElement; | 661 final BoxLocal boxElement; |
| 660 final Map<Local, BoxFieldElement> capturedVariables; | 662 final Map<Local, BoxFieldElement> capturedVariables; |
| 661 | 663 |
| 662 // If the scope is attached to a [For] contains the variables that are | 664 // If the scope is attached to a [For] contains the variables that are |
| 663 // declared in the initializer of the [For] and that need to be boxed. | 665 // declared in the initializer of the [For] and that need to be boxed. |
| 664 // Otherwise contains the empty List. | 666 // Otherwise contains the empty List. |
| 665 List<Local> boxedLoopVariables = const <Local>[]; | 667 List<Local> boxedLoopVariables = const <Local>[]; |
| 666 | 668 |
| 667 ClosureScopeImpl(this.boxElement, this.capturedVariables); | 669 CapturedScopeImpl(this.boxElement, this.capturedVariables); |
| 668 | 670 |
| 669 Local get context => boxElement; | 671 Local get context => boxElement; |
| 670 | 672 |
| 671 bool get requiresContextBox => capturedVariables.keys.isNotEmpty; | 673 bool get requiresContextBox => capturedVariables.keys.isNotEmpty; |
| 672 | 674 |
| 673 void forEachBoxedVariable(f(Local local, FieldEntity field)) { | 675 void forEachBoxedVariable(f(Local local, FieldEntity field)) { |
| 674 capturedVariables.forEach(f); | 676 capturedVariables.forEach(f); |
| 675 } | 677 } |
| 676 | 678 |
| 677 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; | 679 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; |
| 678 | 680 |
| 679 bool isBoxed(Local variable) { | 681 bool isBoxed(Local variable) { |
| 680 return capturedVariables.containsKey(variable); | 682 return capturedVariables.containsKey(variable); |
| 681 } | 683 } |
| 682 | 684 |
| 683 void forEachCapturedVariable( | 685 void forEachCapturedVariable( |
| 684 f(LocalVariableElement variable, BoxFieldElement boxField)) { | 686 f(LocalVariableElement variable, BoxFieldElement boxField)) { |
| 685 capturedVariables.forEach(f); | 687 capturedVariables.forEach(f); |
| 686 } | 688 } |
| 687 | 689 |
| 688 // Should not be called. Added to make the new interface happy. | 690 // Should not be called. Added to make the new interface happy. |
| 689 bool localIsUsedInTryOrSync(Local variable) => | 691 bool localIsUsedInTryOrSync(Local variable) => |
| 690 throw new UnsupportedError("ClosureScopeImpl.localIsUsedInTryOrSync"); | 692 throw new UnsupportedError("CapturedScopeImpl.localIsUsedInTryOrSync"); |
| 691 | 693 |
| 692 // Should not be called. Added to make the new interface happy. | 694 // Should not be called. Added to make the new interface happy. |
| 693 Local get thisLocal => | 695 Local get thisLocal => |
| 694 throw new UnsupportedError("ClosureScopeImpl.thisLocal"); | 696 throw new UnsupportedError("CapturedScopeImpl.thisLocal"); |
| 695 | 697 |
| 696 String toString() { | 698 String toString() { |
| 697 String separator = ''; | 699 String separator = ''; |
| 698 StringBuffer sb = new StringBuffer(); | 700 StringBuffer sb = new StringBuffer(); |
| 699 sb.write('ClosureScopeImpl('); | 701 sb.write('CapturedScopeImpl('); |
| 700 if (boxElement != null) { | 702 if (boxElement != null) { |
| 701 sb.write('box=$boxElement'); | 703 sb.write('box=$boxElement'); |
| 702 separator = ','; | 704 separator = ','; |
| 703 } | 705 } |
| 704 if (boxedLoopVariables.isNotEmpty) { | 706 if (boxedLoopVariables.isNotEmpty) { |
| 705 sb.write(separator); | 707 sb.write(separator); |
| 706 sb.write('boxedLoopVariables=${boxedLoopVariables}'); | 708 sb.write('boxedLoopVariables=${boxedLoopVariables}'); |
| 707 separator = ','; | 709 separator = ','; |
| 708 } | 710 } |
| 709 if (capturedVariables.isNotEmpty) { | 711 if (capturedVariables.isNotEmpty) { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 733 final MethodElement callMethod; | 735 final MethodElement callMethod; |
| 734 | 736 |
| 735 /// The [thisLocal] makes handling 'this' easier by treating it like any | 737 /// The [thisLocal] makes handling 'this' easier by treating it like any |
| 736 /// other argument. It is only set for instance-members. | 738 /// other argument. It is only set for instance-members. |
| 737 final ThisLocal thisLocal; | 739 final ThisLocal thisLocal; |
| 738 | 740 |
| 739 /// Maps free locals, arguments, function elements, and box locals to | 741 /// Maps free locals, arguments, function elements, and box locals to |
| 740 /// their locations. | 742 /// their locations. |
| 741 final Map<Local, FieldEntity> freeVariableMap = new Map<Local, FieldEntity>(); | 743 final Map<Local, FieldEntity> freeVariableMap = new Map<Local, FieldEntity>(); |
| 742 | 744 |
| 743 /// Maps [Loop] and [FunctionExpression] nodes to their [ClosureScopeImpl] whi
ch | 745 /// Maps [Loop] and [FunctionExpression] nodes to their [CapturedScopeImpl] wh
ich |
| 744 /// contains their box and the captured variables that are stored in the box. | 746 /// contains their box and the captured variables that are stored in the box. |
| 745 /// This map will be empty if the method/closure of this [ClosureData] does | 747 /// This map will be empty if the method/closure of this [ClosureData] does |
| 746 /// not contain any nested closure. | 748 /// not contain any nested closure. |
| 747 final Map<Node, ClosureScopeImpl> capturingScopes = | 749 final Map<Node, CapturedScopeImpl> capturingScopes = |
| 748 new Map<Node, ClosureScopeImpl>(); | 750 new Map<Node, CapturedScopeImpl>(); |
| 749 | 751 |
| 750 /// Set of [variable]s referenced in this scope that are used inside a | 752 /// Set of [variable]s referenced in this scope that are used inside a |
| 751 /// `try` block or a `sync*` generator (this is important to know because | 753 /// `try` block or a `sync*` generator (this is important to know because |
| 752 /// boxing/redirection needs to happen for those local variables). | 754 /// boxing/redirection needs to happen for those local variables). |
| 753 /// | 755 /// |
| 754 /// Variables that are used in a try must be treated as boxed because the | 756 /// Variables that are used in a try must be treated as boxed because the |
| 755 /// control flow can be non-linear. | 757 /// control flow can be non-linear. |
| 756 /// | 758 /// |
| 757 /// Also parameters to a `sync*` generator must be boxed, because of the way | 759 /// Also parameters to a `sync*` generator must be boxed, because of the way |
| 758 /// we rewrite sync* functions. See also comments in [useLocal]. | 760 /// we rewrite sync* functions. See also comments in [useLocal]. |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 809 return true; | 811 return true; |
| 810 } | 812 } |
| 811 return capturingScopesBox(variable); | 813 return capturingScopesBox(variable); |
| 812 } | 814 } |
| 813 | 815 |
| 814 void forEachCapturedVariable(void f(Local variable, FieldEntity field)) { | 816 void forEachCapturedVariable(void f(Local variable, FieldEntity field)) { |
| 815 freeVariableMap.forEach((variable, copy) { | 817 freeVariableMap.forEach((variable, copy) { |
| 816 if (variable is BoxLocal) return; | 818 if (variable is BoxLocal) return; |
| 817 f(variable, copy); | 819 f(variable, copy); |
| 818 }); | 820 }); |
| 819 capturingScopes.values.forEach((ClosureScopeImpl scope) { | 821 capturingScopes.values.forEach((CapturedScopeImpl scope) { |
| 820 scope.forEachCapturedVariable(f); | 822 scope.forEachCapturedVariable(f); |
| 821 }); | 823 }); |
| 822 } | 824 } |
| 823 | 825 |
| 824 void forEachBoxedVariable( | 826 void forEachBoxedVariable( |
| 825 void f(LocalVariableElement local, BoxFieldElement field)) { | 827 void f(LocalVariableElement local, BoxFieldElement field)) { |
| 826 freeVariableMap.forEach((variable, copy) { | 828 freeVariableMap.forEach((variable, copy) { |
| 827 if (!isVariableBoxed(variable)) return; | 829 if (!isVariableBoxed(variable)) return; |
| 828 f(variable, copy); | 830 f(variable, copy); |
| 829 }); | 831 }); |
| 830 capturingScopes.values.forEach((ClosureScopeImpl scope) { | 832 capturingScopes.values.forEach((CapturedScopeImpl scope) { |
| 831 scope.forEachCapturedVariable(f); | 833 scope.forEachCapturedVariable(f); |
| 832 }); | 834 }); |
| 833 } | 835 } |
| 834 | 836 |
| 835 bool isBoxed(Local local) { | 837 bool isBoxed(Local local) { |
| 836 bool variableIsBoxed = false; | 838 bool variableIsBoxed = false; |
| 837 forEachBoxedVariable((LocalVariableElement element, BoxFieldElement field) { | 839 forEachBoxedVariable((LocalVariableElement element, BoxFieldElement field) { |
| 838 if (element == local) variableIsBoxed = true; | 840 if (element == local) variableIsBoxed = true; |
| 839 }); | 841 }); |
| 840 return variableIsBoxed; | 842 return variableIsBoxed; |
| 841 } | 843 } |
| 842 } | 844 } |
| 843 | 845 |
| 844 class ClosureTranslator extends Visitor { | 846 class ClosureTranslator extends Visitor { |
| 845 final Compiler compiler; | 847 final Compiler compiler; |
| 846 final ClosedWorldRefiner closedWorldRefiner; | 848 final ClosedWorldRefiner closedWorldRefiner; |
| 847 final TreeElements elements; | 849 final TreeElements elements; |
| 848 int closureFieldCounter = 0; | 850 int closureFieldCounter = 0; |
| 849 int boxedFieldCounter = 0; | 851 int boxedFieldCounter = 0; |
| 850 bool inTryStatement = false; | 852 bool inTryStatement = false; |
| 851 | 853 |
| 852 final Map<Element, ClosureClassMap> closureMappingCache; | 854 final Map<Element, ClosureClassMap> closureMappingCache; |
| 853 final Map<Node, ClosureScopeImpl> closureInfo; | 855 final Map<Node, CapturedScopeImpl> closureInfo; |
| 854 | 856 |
| 855 // Map of captured variables. Initially they will map to `null`. If | 857 // Map of captured variables. Initially they will map to `null`. If |
| 856 // a variable needs to be boxed then the scope declaring the variable | 858 // a variable needs to be boxed then the scope declaring the variable |
| 857 // will update this to mapping to the capturing [BoxFieldElement]. | 859 // will update this to mapping to the capturing [BoxFieldElement]. |
| 858 Map<Local, BoxFieldElement> _capturedVariableMapping = | 860 Map<Local, BoxFieldElement> _capturedVariableMapping = |
| 859 new Map<Local, BoxFieldElement>(); | 861 new Map<Local, BoxFieldElement>(); |
| 860 | 862 |
| 861 // List of encountered closures. | 863 // List of encountered closures. |
| 862 List<LocalFunctionElement> closures = <LocalFunctionElement>[]; | 864 List<LocalFunctionElement> closures = <LocalFunctionElement>[]; |
| 863 | 865 |
| (...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1254 } | 1256 } |
| 1255 } | 1257 } |
| 1256 | 1258 |
| 1257 for (LocalVariableElement variable in scopeVariables) { | 1259 for (LocalVariableElement variable in scopeVariables) { |
| 1258 // No need to box non-assignable elements. | 1260 // No need to box non-assignable elements. |
| 1259 if (!variable.isAssignable) continue; | 1261 if (!variable.isAssignable) continue; |
| 1260 if (!mutatedVariables.contains(variable)) continue; | 1262 if (!mutatedVariables.contains(variable)) continue; |
| 1261 boxCapturedVariable(variable); | 1263 boxCapturedVariable(variable); |
| 1262 } | 1264 } |
| 1263 if (!scopeMapping.isEmpty) { | 1265 if (!scopeMapping.isEmpty) { |
| 1264 ClosureScopeImpl scope = new ClosureScopeImpl(box, scopeMapping); | 1266 CapturedScopeImpl scope = new CapturedScopeImpl(box, scopeMapping); |
| 1265 closureData.capturingScopes[node] = scope; | 1267 closureData.capturingScopes[node] = scope; |
| 1266 assert(closureInfo[node] == null); | 1268 assert(closureInfo[node] == null); |
| 1267 closureInfo[node] = scope; | 1269 closureInfo[node] = scope; |
| 1268 } | 1270 } |
| 1269 } | 1271 } |
| 1270 | 1272 |
| 1271 void inNewScope(Node node, Function action) { | 1273 void inNewScope(Node node, Function action) { |
| 1272 List<LocalVariableElement> oldScopeVariables = scopeVariables; | 1274 List<LocalVariableElement> oldScopeVariables = scopeVariables; |
| 1273 scopeVariables = <LocalVariableElement>[]; | 1275 scopeVariables = <LocalVariableElement>[]; |
| 1274 action(); | 1276 action(); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1319 link = link.tail) { | 1321 link = link.tail) { |
| 1320 Node definition = link.head; | 1322 Node definition = link.head; |
| 1321 LocalVariableElement element = elements[definition]; | 1323 LocalVariableElement element = elements[definition]; |
| 1322 // Non-mutated variables should not be boxed. The mutatedVariables set | 1324 // Non-mutated variables should not be boxed. The mutatedVariables set |
| 1323 // gets cleared when 'inNewScope' returns, so check it here. | 1325 // gets cleared when 'inNewScope' returns, so check it here. |
| 1324 if (isCapturedVariable(element) && mutatedVariables.contains(element)) { | 1326 if (isCapturedVariable(element) && mutatedVariables.contains(element)) { |
| 1325 boxedLoopVariables.add(element); | 1327 boxedLoopVariables.add(element); |
| 1326 } | 1328 } |
| 1327 } | 1329 } |
| 1328 }); | 1330 }); |
| 1329 ClosureScopeImpl scopeData = closureData.capturingScopes[node]; | 1331 CapturedScopeImpl scopeData = closureData.capturingScopes[node]; |
| 1330 if (scopeData == null) return; | 1332 if (scopeData == null) return; |
| 1331 scopeData.boxedLoopVariables = boxedLoopVariables; | 1333 scopeData.boxedLoopVariables = boxedLoopVariables; |
| 1332 } | 1334 } |
| 1333 | 1335 |
| 1334 /** Returns a non-unique name for the given closure element. */ | 1336 /** Returns a non-unique name for the given closure element. */ |
| 1335 String computeClosureName(Element element) { | 1337 String computeClosureName(Element element) { |
| 1336 Link<String> parts = const Link<String>(); | 1338 Link<String> parts = const Link<String>(); |
| 1337 String ownName = element.name; | 1339 String ownName = element.name; |
| 1338 if (ownName == null || ownName == "") { | 1340 if (ownName == null || ownName == "") { |
| 1339 parts = parts.prepend("closure"); | 1341 parts = parts.prepend("closure"); |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1539 /// | 1541 /// |
| 1540 /// Move the below classes to a JS model eventually. | 1542 /// Move the below classes to a JS model eventually. |
| 1541 /// | 1543 /// |
| 1542 abstract class JSEntity implements MemberEntity { | 1544 abstract class JSEntity implements MemberEntity { |
| 1543 Local get declaredEntity; | 1545 Local get declaredEntity; |
| 1544 } | 1546 } |
| 1545 | 1547 |
| 1546 abstract class PrivatelyNamedJSEntity implements JSEntity { | 1548 abstract class PrivatelyNamedJSEntity implements JSEntity { |
| 1547 Entity get rootOfScope; | 1549 Entity get rootOfScope; |
| 1548 } | 1550 } |
| OLD | NEW |