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 |