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 library closureToClassMapper; | 5 library closureToClassMapper; |
6 | 6 |
7 import 'common/names.dart' show Identifiers; | 7 import 'common/names.dart' show Identifiers; |
8 import 'common/resolution.dart' show ParsingContext, Resolution; | 8 import 'common/resolution.dart' show ParsingContext, Resolution; |
9 import 'common/tasks.dart' show CompilerTask; | 9 import 'common/tasks.dart' show CompilerTask; |
10 import 'common.dart'; | 10 import 'common.dart'; |
11 import 'compiler.dart' show Compiler; | 11 import 'compiler.dart' show Compiler; |
12 import 'constants/expressions.dart'; | 12 import 'constants/expressions.dart'; |
13 import 'elements/elements.dart'; | 13 import 'elements/elements.dart'; |
14 import 'elements/entities.dart'; | 14 import 'elements/entities.dart'; |
15 import 'elements/entity_utils.dart' as utils; | 15 import 'elements/entity_utils.dart' as utils; |
16 import 'elements/modelx.dart' | 16 import 'elements/modelx.dart' |
17 show BaseFunctionElementX, ClassElementX, ElementX; | 17 show BaseFunctionElementX, ClassElementX, ElementX; |
18 import 'elements/resolution_types.dart'; | 18 import 'elements/resolution_types.dart'; |
19 import 'elements/types.dart'; | 19 import 'elements/types.dart'; |
20 import 'elements/visitor.dart' show ElementVisitor; | 20 import 'elements/visitor.dart' show ElementVisitor; |
21 import 'js_backend/js_backend.dart' show JavaScriptBackend; | 21 import 'js_backend/js_backend.dart' show JavaScriptBackend; |
22 import 'resolution/tree_elements.dart' show TreeElements; | 22 import 'resolution/tree_elements.dart' show TreeElements; |
23 import 'package:front_end/src/fasta/scanner.dart' show Token; | 23 import 'package:front_end/src/fasta/scanner.dart' show Token; |
24 import 'tree/tree.dart'; | 24 import 'tree/tree.dart'; |
25 import 'util/util.dart'; | 25 import 'util/util.dart'; |
26 import 'world.dart' show ClosedWorldRefiner; | 26 import 'world.dart' show ClosedWorldRefiner; |
27 | 27 |
28 /// Where T is ir.Node or Node. | 28 /// Where T is ir.Node or Node. |
29 // TODO(efortuna): Rename this class. | |
29 abstract class ClosureClassMaps<T> { | 30 abstract class ClosureClassMaps<T> { |
30 ClosureClassMap getMemberMap(MemberEntity member); | 31 /// Look up information about the variables that have been mutated and are |
31 ClosureClassMap getLocalFunctionMap(Local localFunction); | 32 /// used inside the scope of [node]. |
33 // TODO(johnniwinther): Split this up into two functions, one for members and | |
34 // one for local functions. | |
35 ClosureRepresentationInfo getClosureRepresentationInfo(Entity member); | |
32 | 36 |
33 /// Look up information about a loop, in case any variables it declares need | 37 /// Look up information about a loop, in case any variables it declares need |
34 /// to be boxed/snapshotted. | 38 /// to be boxed/snapshotted. |
35 LoopClosureRepresentationInfo getClosureRepresentationInfoForLoop(T loopNode); | 39 LoopClosureRepresentationInfo getClosureRepresentationInfoForLoop(T loopNode); |
36 | 40 |
37 /// Accessor to the information about closures that the SSA builder will use. | 41 /// Accessor to the information about closures that the SSA builder will use. |
38 ClosureAnalysisInfo getClosureAnalysisInfo(T node); | 42 ClosureAnalysisInfo getClosureAnalysisInfo(T node); |
39 } | 43 } |
40 | 44 |
41 /// Class that provides a black-box interface to information gleaned from | 45 /// Class that provides a black-box interface to information gleaned from |
(...skipping 27 matching lines...) Expand all Loading... | |
69 } | 73 } |
70 | 74 |
71 /// Class that describes the actual mechanics of how a loop is | 75 /// Class that describes the actual mechanics of how a loop is |
72 /// converted/rewritten without closures. Unlike JS, the value of a declared | 76 /// converted/rewritten without closures. Unlike JS, the value of a declared |
73 /// loop iteration variable in any closure is captured/snapshotted inside at | 77 /// loop iteration variable in any closure is captured/snapshotted inside at |
74 /// each iteration point, as if we created a new local variable for that value | 78 /// each iteration point, as if we created a new local variable for that value |
75 /// inside the loop. For example, for the following loop: | 79 /// inside the loop. For example, for the following loop: |
76 /// | 80 /// |
77 /// var lst = []; | 81 /// var lst = []; |
78 /// for (int i = 0; i < 5; i++) lst.add(()=>i); | 82 /// for (int i = 0; i < 5; i++) lst.add(()=>i); |
83 /// var result = list.map((f) => f()).toList(); | |
79 /// | 84 /// |
80 /// The result of `lst` will be [0, 1, 2, 3, 4], whereas were this JS code | 85 /// `result` will be [0, 1, 2, 3, 4], whereas were this JS code |
81 /// the result would be [5, 5, 5, 5, 5]. Because of this difference we need to | 86 /// the result would be [5, 5, 5, 5, 5]. Because of this difference we need to |
82 /// create a closure for these sorts of loops to capture the variable's value at | 87 /// create a closure for these sorts of loops to capture the variable's value at |
83 /// each iteration, by boxing the iteration variable[s]. | 88 /// each iteration, by boxing the iteration variable[s]. |
84 class LoopClosureRepresentationInfo extends ClosureAnalysisInfo { | 89 class LoopClosureRepresentationInfo extends ClosureAnalysisInfo { |
85 const LoopClosureRepresentationInfo(); | 90 const LoopClosureRepresentationInfo(); |
86 | 91 |
87 /// True if this loop declares any variables that need to be boxed. | 92 /// True if this loop declares any variables that need to be boxed. |
88 bool get hasBoxedVariables => false; | 93 bool get hasBoxedVariables => false; |
89 | 94 |
90 /// The set of iteration variables (or variables declared in the for loop | 95 /// The set of iteration variables (or variables declared in the for loop |
91 /// expression (`for (...here...)`) that need to be boxed to snapshot their | 96 /// expression (`for (...here...)`) that need to be boxed to snapshot their |
92 /// value. | 97 /// value. |
93 List<Local> get boxedVariables => const <Local>[]; | 98 List<Local> get boxedVariables => const <Local>[]; |
94 } | 99 } |
95 | 100 |
101 /// Class that describes the actual mechanics of how the converted, rewritten | |
Siggi Cherem (dart-lang)
2017/06/14 22:56:36
brainstorming here: in a way I think "convertion/r
Emily Fortuna
2017/06/15 00:11:22
"Closure Conversion" is the standard term used to
| |
102 /// closure is implemented. For example, for the following closure (named foo | |
103 /// for convenience): | |
104 /// | |
105 /// var foo = (x) => y + x; | |
106 /// | |
107 /// We would produce the following class to control access to these variables in | |
108 /// the following way (modulo naming of variables, assuming that y is modified | |
109 /// elsewhere in its scope): | |
110 /// | |
111 /// class FooClosure { | |
112 /// int y; | |
113 /// FooClosure(this.y); | |
114 /// call(x) => this.y + x; | |
115 /// } | |
116 /// | |
117 /// and then to execute this closure, for example: | |
118 /// | |
119 /// var foo = new FooClosure(1); | |
120 /// foo.call(2); | |
121 /// | |
122 /// if y is modified elsewhere within its scope, accesses to y anywhere in the | |
123 /// code will be controlled via a box object. | |
124 /// TODO(efortuna): Make interface simpler in subsequent refactorings. | |
125 class ClosureRepresentationInfo { | |
126 const ClosureRepresentationInfo(); | |
127 | |
128 /// The original local function before any translation. | |
129 /// | |
130 /// Will be null for methods. | |
131 Local get closureEntity => null; | |
132 | |
133 /// Closures are rewritten in the form of classes that have fields to control | |
Siggi Cherem (dart-lang)
2017/06/14 22:56:36
minor nit: consider moving up the sentence that ju
Emily Fortuna
2017/06/15 00:11:22
Cool. I updated the docs in this CL: https://coder
| |
134 /// the redirection and editing of variables that are "captured" inside a | |
135 /// scope (declared in an outer scope but used in an inside scope). So this | |
136 /// returns the class entity that represents this particular rewritten | |
137 /// closure. | |
138 ClassEntity get closureClassEntity => null; | |
139 | |
140 /// The function that implements the [local] function as a `call` method on | |
141 /// the closure class. | |
142 FunctionEntity get callMethod => null; | |
143 | |
144 /// As shown in the example in the comments at the top of this class, we | |
145 /// create fields in the closure class for each captured variable. This is an | |
146 /// accessor to that set of fields. | |
147 List<Local> get createdFieldEntities => const <Local>[]; | |
148 | |
149 /// Convenience reference pointer to the element representing `this`. | |
150 /// It is only set for instance-members. | |
151 Local get thisLocal => null; | |
152 | |
153 /// Convenience pointer to the field entity representation in the closure | |
154 /// class of the element representing `this`. | |
155 FieldEntity get thisFieldEntity => null; | |
156 | |
157 /// Returns true if this [variable] is used inside a `try` block or a `sync*` | |
158 /// generator (this is important to know because boxing/redirection needs to | |
159 /// happen for those local variables). | |
160 /// | |
161 /// Variables that are used in a try must be treated as boxed because the | |
162 /// control flow can be non-linear. | |
163 /// | |
164 /// Also parameters to a `sync*` generator must be boxed, because of the way | |
165 /// we rewrite sync* functions. See also comments in | |
166 /// [ClosureClassMap.useLocal]. | |
167 bool variableIsUsedInTryOrSync(Local variable) => false; | |
168 | |
169 /// Loop through every variable that has been captured in this closure. This | |
170 /// consists of all the free variables (variables captured *just* in this | |
171 /// closure) and all variables captured in nested scopes that we may be | |
172 /// capturing as well. These nested scopes hold "boxes" to hold the executable | |
173 /// context for that scope. | |
174 void forEachCapturedVariable(f(Local from, FieldEntity to)) {} | |
175 | |
176 /// Loop through each variable that has been boxed in this closure class. Only | |
177 /// captured variables that are mutated need to be "boxed" (which basically | |
178 /// puts a thin layer between updates and reads to this variable to ensure | |
179 /// that every place that accesses it gets the correct updated value). | |
180 void forEachBoxedVariable(f(Local local, FieldEntity field)) {} | |
181 | |
182 /// Loop through each free variable in this closure. Free variables are the | |
183 /// variables that have been captured *just* in this closure, not in nested | |
184 /// scopes. | |
185 void forEachFreeVariable(f(Local variable, FieldEntity field)) {} | |
186 | |
187 /// Return true if [variable] has been captured and mutated (all other | |
188 /// variables do not require boxing). | |
189 bool isVariableBoxed(Local variable) => false; | |
190 | |
191 // TODO(efortuna): Remove this method. The old system was using | |
192 // ClosureClassMaps for situations other than closure class maps, and that's | |
193 // just confusing. | |
194 bool get isClosure => false; | |
195 } | |
196 | |
96 class ClosureTask extends CompilerTask implements ClosureClassMaps<Node> { | 197 class ClosureTask extends CompilerTask implements ClosureClassMaps<Node> { |
97 Map<Node, ClosureScope> _closureInfoMap = <Node, ClosureScope>{}; | 198 Map<Node, ClosureScope> _closureInfoMap = <Node, ClosureScope>{}; |
98 Map<Element, ClosureClassMap> _closureMappingCache = | 199 Map<Element, ClosureClassMap> _closureMappingCache = |
99 <Element, ClosureClassMap>{}; | 200 <Element, ClosureClassMap>{}; |
100 Compiler compiler; | 201 Compiler compiler; |
101 ClosureTask(Compiler compiler) | 202 ClosureTask(Compiler compiler) |
102 : compiler = compiler, | 203 : compiler = compiler, |
103 super(compiler.measurer); | 204 super(compiler.measurer); |
104 | 205 |
105 String get name => "Closure Simplifier"; | 206 String get name => "Closure Simplifier"; |
106 | 207 |
107 DiagnosticReporter get reporter => compiler.reporter; | 208 DiagnosticReporter get reporter => compiler.reporter; |
108 | 209 |
109 ClosureAnalysisInfo getClosureAnalysisInfo(Node node) { | 210 ClosureAnalysisInfo getClosureAnalysisInfo(Node node) { |
110 var value = _closureInfoMap[node]; | 211 var value = _closureInfoMap[node]; |
111 return value == null ? const ClosureAnalysisInfo() : value; | 212 return value == null ? const ClosureAnalysisInfo() : value; |
112 } | 213 } |
113 | 214 |
215 ClosureRepresentationInfo getClosureRepresentationInfo(Element member) { | |
216 return getClosureToClassMapping(member); | |
217 } | |
218 | |
114 LoopClosureRepresentationInfo getClosureRepresentationInfoForLoop( | 219 LoopClosureRepresentationInfo getClosureRepresentationInfoForLoop( |
115 Node loopNode) { | 220 Node loopNode) { |
116 var value = _closureInfoMap[loopNode]; | 221 var value = _closureInfoMap[loopNode]; |
117 return value == null ? const LoopClosureRepresentationInfo() : value; | 222 return value == null ? const LoopClosureRepresentationInfo() : value; |
118 } | 223 } |
119 | 224 |
120 ClosureClassMap getMemberMap(MemberElement member) { | |
121 return getClosureToClassMapping(member); | |
122 } | |
123 | |
124 ClosureClassMap getLocalFunctionMap(LocalFunctionElement localFunction) { | |
125 return getClosureToClassMapping(localFunction); | |
126 } | |
127 | |
128 /// Returns the [ClosureClassMap] computed for [resolvedAst]. | 225 /// Returns the [ClosureClassMap] computed for [resolvedAst]. |
129 ClosureClassMap getClosureToClassMapping(Element element) { | 226 ClosureClassMap getClosureToClassMapping(Element element) { |
130 return measure(() { | 227 return measure(() { |
131 if (element.isGenerativeConstructorBody) { | 228 if (element.isGenerativeConstructorBody) { |
132 ConstructorBodyElement constructorBody = element; | 229 ConstructorBodyElement constructorBody = element; |
133 element = constructorBody.constructor; | 230 element = constructorBody.constructor; |
134 } | 231 } |
135 ClosureClassMap closureClassMap = _closureMappingCache[element]; | 232 ClosureClassMap closureClassMap = _closureMappingCache[element]; |
136 assert(closureClassMap != null, | 233 assert(closureClassMap != null, |
137 failedAt(element, "No ClosureClassMap computed for ${element}.")); | 234 failedAt(element, "No ClosureClassMap computed for ${element}.")); |
(...skipping 392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
530 } | 627 } |
531 if (capturedVariables.isNotEmpty) { | 628 if (capturedVariables.isNotEmpty) { |
532 sb.write(separator); | 629 sb.write(separator); |
533 sb.write('capturedVariables=$capturedVariables'); | 630 sb.write('capturedVariables=$capturedVariables'); |
534 } | 631 } |
535 sb.write(')'); | 632 sb.write(')'); |
536 return sb.toString(); | 633 return sb.toString(); |
537 } | 634 } |
538 } | 635 } |
539 | 636 |
540 class ClosureClassMap { | 637 class ClosureClassMap implements ClosureRepresentationInfo { |
541 /// The local function element before any translation. | 638 /// The local function element before any translation. |
542 /// | 639 /// |
543 /// Will be null for methods. | 640 /// Will be null for methods. |
544 final LocalFunctionElement closureElement; | 641 final LocalFunctionElement closureEntity; |
545 | 642 |
546 /// The synthesized closure class for [closureElement]. | 643 /// The synthesized closure class for [closureEntity]. |
547 /// | 644 /// |
548 /// The closureClassElement will be null for methods that are not local | 645 /// The closureClassEntity will be null for methods that are not local |
549 /// closures. | 646 /// closures. |
550 final ClosureClassElement closureClassElement; | 647 final ClosureClassElement closureClassEntity; |
551 | 648 |
552 /// The synthesized `call` method of the [ closureClassElement]. | 649 /// The synthesized `call` method of the [closureClassEntity]. |
553 /// | 650 /// |
554 /// The callElement will be null for methods that are not local closures. | 651 /// The callMethod will be null for methods that are not local closures. |
555 final MethodElement callElement; | 652 final MethodElement callMethod; |
556 | 653 |
557 /// The [thisElement] makes handling 'this' easier by treating it like any | 654 /// The [thisLocal] makes handling 'this' easier by treating it like any |
558 /// other argument. It is only set for instance-members. | 655 /// other argument. It is only set for instance-members. |
559 final ThisLocal thisLocal; | 656 final ThisLocal thisLocal; |
560 | 657 |
561 /// Maps free locals, arguments, function elements, and box locals to | 658 /// Maps free locals, arguments, function elements, and box locals to |
562 /// their locations. | 659 /// their locations. |
563 final Map<Local, FieldEntity> freeVariableMap = new Map<Local, FieldEntity>(); | 660 final Map<Local, FieldEntity> freeVariableMap = new Map<Local, FieldEntity>(); |
564 | 661 |
565 /// Maps [Loop] and [FunctionExpression] nodes to their [ClosureScope] which | 662 /// Maps [Loop] and [FunctionExpression] nodes to their [ClosureScope] which |
566 /// contains their box and the captured variables that are stored in the box. | 663 /// contains their box and the captured variables that are stored in the box. |
567 /// This map will be empty if the method/closure of this [ClosureData] does | 664 /// This map will be empty if the method/closure of this [ClosureData] does |
568 /// not contain any nested closure. | 665 /// not contain any nested closure. |
569 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); | 666 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); |
570 | 667 |
571 /// Variables that are used in a try must be treated as boxed because the | 668 /// Variables that are used in a try must be treated as boxed because the |
572 /// control flow can be non-linear. | 669 /// control flow can be non-linear. |
573 /// | 670 /// |
574 /// Also parameters to a `sync*` generator must be boxed, because of the way | 671 /// Also parameters to a `sync*` generator must be boxed, because of the way |
575 /// we rewrite sync* functions. See also comments in [useLocal]. | 672 /// we rewrite sync* functions. See also comments in [useLocal]. |
576 // TODO(johnniwinther): Add variables to this only if the variable is mutated. | 673 // TODO(johnniwinther): Add variables to this only if the variable is mutated. |
577 final Set<Local> variablesUsedInTryOrGenerator = new Set<Local>(); | 674 final Set<Local> variablesUsedInTryOrGenerator = new Set<Local>(); |
578 | 675 |
579 ClosureClassMap(this.closureElement, this.closureClassElement, | 676 ClosureClassMap(this.closureEntity, this.closureClassEntity, this.callMethod, |
580 this.callElement, this.thisLocal); | 677 this.thisLocal); |
678 | |
679 List<Local> get createdFieldEntities { | |
680 List<Local> fields = <Local>[]; | |
681 if (closureClassEntity == null) return const <Local>[]; | |
682 closureClassEntity.closureFields.forEach((field) { | |
683 fields.add(field.local); | |
684 }); | |
685 return fields; | |
686 } | |
581 | 687 |
582 void addFreeVariable(Local element) { | 688 void addFreeVariable(Local element) { |
583 assert(freeVariableMap[element] == null); | 689 assert(freeVariableMap[element] == null); |
584 freeVariableMap[element] = null; | 690 freeVariableMap[element] = null; |
585 } | 691 } |
586 | 692 |
587 Iterable<Local> get freeVariables => freeVariableMap.keys; | 693 Iterable<Local> get freeVariables => freeVariableMap.keys; |
588 | 694 |
589 bool isFreeVariable(Local element) { | 695 bool isFreeVariable(Local element) { |
590 return freeVariableMap.containsKey(element); | 696 return freeVariableMap.containsKey(element); |
591 } | 697 } |
592 | 698 |
593 void forEachFreeVariable(f(Local variable, FieldEntity field)) { | 699 void forEachFreeVariable(f(Local variable, FieldEntity field)) { |
594 freeVariableMap.forEach(f); | 700 freeVariableMap.forEach(f); |
595 } | 701 } |
596 | 702 |
597 bool isVariableUsedInTryOrSync(Local variable) => | 703 FieldEntity get thisFieldEntity => freeVariableMap[thisLocal]; |
704 | |
705 bool variableIsUsedInTryOrSync(Local variable) => | |
598 variablesUsedInTryOrGenerator.contains(variable); | 706 variablesUsedInTryOrGenerator.contains(variable); |
599 | 707 |
600 Local getLocalVariableForClosureField(ClosureFieldElement field) { | 708 Local getLocalVariableForClosureField(ClosureFieldElement field) { |
601 return field.local; | 709 return field.local; |
602 } | 710 } |
603 | 711 |
604 bool get isClosure => closureElement != null; | 712 bool get isClosure => closureEntity != null; |
605 | 713 |
606 bool capturingScopesBox(Local variable) { | 714 bool capturingScopesBox(Local variable) { |
607 return capturingScopes.values.any((scope) { | 715 return capturingScopes.values.any((scope) { |
608 return scope.boxedLoopVariables.contains(variable); | 716 return scope.boxedLoopVariables.contains(variable); |
609 }); | 717 }); |
610 } | 718 } |
611 | 719 |
612 bool isVariableBoxed(Local variable) { | 720 bool isVariableBoxed(Local variable) { |
613 FieldEntity copy = freeVariableMap[variable]; | 721 FieldEntity copy = freeVariableMap[variable]; |
614 if (copy is BoxFieldElement) { | 722 if (copy is BoxFieldElement) { |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
771 if (boxFieldElement == null) { | 879 if (boxFieldElement == null) { |
772 assert(fromElement is! BoxLocal); | 880 assert(fromElement is! BoxLocal); |
773 // The variable has not been boxed. | 881 // The variable has not been boxed. |
774 fieldCaptures.add(fromElement); | 882 fieldCaptures.add(fromElement); |
775 } else { | 883 } else { |
776 // A boxed element. | 884 // A boxed element. |
777 data.freeVariableMap[fromElement] = boxFieldElement; | 885 data.freeVariableMap[fromElement] = boxFieldElement; |
778 boxes.add(boxFieldElement.box); | 886 boxes.add(boxFieldElement.box); |
779 } | 887 } |
780 }); | 888 }); |
781 ClosureClassElement closureClass = data.closureClassElement; | 889 ClosureClassElement closureClass = data.closureClassEntity; |
782 assert(closureClass != null || (fieldCaptures.isEmpty && boxes.isEmpty)); | 890 assert(closureClass != null || (fieldCaptures.isEmpty && boxes.isEmpty)); |
783 | 891 |
784 void addClosureField(Local local, String name) { | 892 void addClosureField(Local local, String name) { |
785 ClosureFieldElement closureField = | 893 ClosureFieldElement closureField = |
786 new ClosureFieldElement(name, local, closureClass); | 894 new ClosureFieldElement(name, local, closureClass); |
787 closureClass.addField(closureField, reporter); | 895 closureClass.addField(closureField, reporter); |
788 data.freeVariableMap[local] = closureField; | 896 data.freeVariableMap[local] = closureField; |
789 } | 897 } |
790 | 898 |
791 // Add the box elements first so we get the same ordering. | 899 // Add the box elements first so we get the same ordering. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
827 variable.executableContext == executableContext; | 935 variable.executableContext == executableContext; |
828 } | 936 } |
829 | 937 |
830 if (insideClosure && !inCurrentContext(variable)) { | 938 if (insideClosure && !inCurrentContext(variable)) { |
831 closureData.addFreeVariable(variable); | 939 closureData.addFreeVariable(variable); |
832 } else if (inTryStatement) { | 940 } else if (inTryStatement) { |
833 // Don't mark the this-element or a self-reference. This would complicate | 941 // Don't mark the this-element or a self-reference. This would complicate |
834 // things in the builder. | 942 // things in the builder. |
835 // Note that nested (named) functions are immutable. | 943 // Note that nested (named) functions are immutable. |
836 if (variable != closureData.thisLocal && | 944 if (variable != closureData.thisLocal && |
837 variable != closureData.closureElement && | 945 variable != closureData.closureEntity && |
838 variable is! TypeVariableLocal) { | 946 variable is! TypeVariableLocal) { |
839 closureData.variablesUsedInTryOrGenerator.add(variable); | 947 closureData.variablesUsedInTryOrGenerator.add(variable); |
840 } | 948 } |
841 } else if (variable is LocalParameterElement && | 949 } else if (variable is LocalParameterElement && |
842 variable.functionDeclaration.asyncMarker == AsyncMarker.SYNC_STAR) { | 950 variable.functionDeclaration.asyncMarker == AsyncMarker.SYNC_STAR) { |
843 // Parameters in a sync* function are shared between each Iterator created | 951 // Parameters in a sync* function are shared between each Iterator created |
844 // by the Iterable returned by the function, therefore they must be boxed. | 952 // by the Iterable returned by the function, therefore they must be boxed. |
845 closureData.variablesUsedInTryOrGenerator.add(variable); | 953 closureData.variablesUsedInTryOrGenerator.add(variable); |
846 } | 954 } |
847 } | 955 } |
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1214 thisElement = new ThisLocal(member); | 1322 thisElement = new ThisLocal(member); |
1215 } | 1323 } |
1216 closureData = new ClosureClassMap(null, null, null, thisElement); | 1324 closureData = new ClosureClassMap(null, null, null, thisElement); |
1217 if (element is MethodElement) { | 1325 if (element is MethodElement) { |
1218 needsRti = compiler.options.enableTypeAssertions || | 1326 needsRti = compiler.options.enableTypeAssertions || |
1219 compiler.backend.rtiNeed.methodNeedsRti(element); | 1327 compiler.backend.rtiNeed.methodNeedsRti(element); |
1220 } | 1328 } |
1221 } | 1329 } |
1222 closureMappingCache[element] = closureData; | 1330 closureMappingCache[element] = closureData; |
1223 closureMappingCache[element.declaration] = closureData; | 1331 closureMappingCache[element.declaration] = closureData; |
1224 if (closureData.callElement != null) { | 1332 if (closureData.callMethod != null) { |
1225 closureMappingCache[closureData.callElement] = closureData; | 1333 closureMappingCache[closureData.callMethod] = closureData; |
1226 } | 1334 } |
1227 | 1335 |
1228 inNewScope(node, () { | 1336 inNewScope(node, () { |
1229 // If the method needs RTI, or checked mode is set, we need to | 1337 // If the method needs RTI, or checked mode is set, we need to |
1230 // escape the potential type variables used in that closure. | 1338 // escape the potential type variables used in that closure. |
1231 if (needsRti) { | 1339 if (needsRti) { |
1232 analyzeTypeVariables(element.type); | 1340 analyzeTypeVariables(element.type); |
1233 } | 1341 } |
1234 | 1342 |
1235 visitChildren(); | 1343 visitChildren(); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1335 /// | 1443 /// |
1336 /// Move the below classes to a JS model eventually. | 1444 /// Move the below classes to a JS model eventually. |
1337 /// | 1445 /// |
1338 abstract class JSEntity implements MemberEntity { | 1446 abstract class JSEntity implements MemberEntity { |
1339 Local get declaredEntity; | 1447 Local get declaredEntity; |
1340 } | 1448 } |
1341 | 1449 |
1342 abstract class PrivatelyNamedJSEntity implements JSEntity { | 1450 abstract class PrivatelyNamedJSEntity implements JSEntity { |
1343 Entity get rootOfScope; | 1451 Entity get rootOfScope; |
1344 } | 1452 } |
OLD | NEW |