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