Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 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 |