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 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 |