OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; |
6 | 6 |
7 import '../closure.dart'; | 7 import '../closure.dart'; |
8 import '../common.dart'; | 8 import '../common.dart'; |
9 import '../common/tasks.dart'; | 9 import '../common/tasks.dart'; |
10 import '../constants/expressions.dart'; | 10 import '../constants/expressions.dart'; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 /// http://matt.might.net/articles/closure-conversion/. | 63 /// http://matt.might.net/articles/closure-conversion/. |
64 // TODO(efortuna): Change inheritance hierarchy so that the | 64 // TODO(efortuna): Change inheritance hierarchy so that the |
65 // ClosureConversionTask doesn't inherit from ClosureTask because it's just a | 65 // ClosureConversionTask doesn't inherit from ClosureTask because it's just a |
66 // glorified timer. | 66 // glorified timer. |
67 class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> { | 67 class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> { |
68 final KernelToElementMapForBuilding _elementMap; | 68 final KernelToElementMapForBuilding _elementMap; |
69 final GlobalLocalsMap _globalLocalsMap; | 69 final GlobalLocalsMap _globalLocalsMap; |
70 final Map<MemberEntity, ScopeModel> _closureModels; | 70 final Map<MemberEntity, ScopeModel> _closureModels; |
71 | 71 |
72 /// Map of the scoping information that corresponds to a particular entity. | 72 /// Map of the scoping information that corresponds to a particular entity. |
73 Map<Entity, ScopeInfo> _scopeMap = <Entity, ScopeInfo>{}; | 73 Map<MemberEntity, ScopeInfo> _scopeMap = <MemberEntity, ScopeInfo>{}; |
74 Map<ir.Node, CapturedScope> _capturedScopesMap = <ir.Node, CapturedScope>{}; | 74 Map<ir.Node, CapturedScope> _capturedScopesMap = <ir.Node, CapturedScope>{}; |
75 | 75 |
76 Map<Entity, ClosureRepresentationInfo> _closureRepresentationMap = | 76 Map<MemberEntity, ClosureRepresentationInfo> _memberClosureRepresentationMap = |
77 <Entity, ClosureRepresentationInfo>{}; | 77 <MemberEntity, ClosureRepresentationInfo>{}; |
| 78 |
| 79 // The key is either a [ir.FunctionDeclaration] or [ir.FunctionExpression]. |
| 80 Map<ir.Node, ClosureRepresentationInfo> _localClosureRepresentationMap = |
| 81 <ir.Node, ClosureRepresentationInfo>{}; |
78 | 82 |
79 KernelClosureConversionTask(Measurer measurer, this._elementMap, | 83 KernelClosureConversionTask(Measurer measurer, this._elementMap, |
80 this._globalLocalsMap, this._closureModels) | 84 this._globalLocalsMap, this._closureModels) |
81 : super(measurer); | 85 : super(measurer); |
82 | 86 |
83 /// The combined steps of generating our intermediate representation of | 87 /// The combined steps of generating our intermediate representation of |
84 /// closures that need to be rewritten and generating the element model. | 88 /// closures that need to be rewritten and generating the element model. |
85 /// Ultimately these two steps will be split apart with the second step | 89 /// Ultimately these two steps will be split apart with the second step |
86 /// happening later in compilation just before codegen. These steps are | 90 /// happening later in compilation just before codegen. These steps are |
87 /// combined here currently to provide a consistent interface to the rest of | 91 /// combined here currently to provide a consistent interface to the rest of |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 MemberEntity member, | 135 MemberEntity member, |
132 ir.FunctionNode node, | 136 ir.FunctionNode node, |
133 KernelScopeInfo info, | 137 KernelScopeInfo info, |
134 JsClosedWorld closedWorldRefiner) { | 138 JsClosedWorld closedWorldRefiner) { |
135 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); | 139 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); |
136 KernelClosureClass closureClass = closedWorldRefiner.buildClosureClass( | 140 KernelClosureClass closureClass = closedWorldRefiner.buildClosureClass( |
137 member, node, member.library, info, node.location, localsMap); | 141 member, node, member.library, info, node.location, localsMap); |
138 | 142 |
139 // We want the original declaration where that function is used to point | 143 // We want the original declaration where that function is used to point |
140 // to the correct closure class. | 144 // to the correct closure class. |
141 _closureRepresentationMap[closureClass.callMethod] = closureClass; | 145 _memberClosureRepresentationMap[closureClass.callMethod] = closureClass; |
142 Entity entity; | |
143 if (node.parent is ir.Member) { | 146 if (node.parent is ir.Member) { |
144 entity = _elementMap.getMember(node.parent); | 147 assert(_elementMap.getMember(node.parent) == member); |
| 148 _memberClosureRepresentationMap[member] = closureClass; |
145 } else { | 149 } else { |
146 entity = localsMap.getLocalFunction(node.parent); | 150 assert(node.parent is ir.FunctionExpression || |
| 151 node.parent is ir.FunctionDeclaration); |
| 152 _localClosureRepresentationMap[node.parent] = closureClass; |
147 } | 153 } |
148 assert(entity != null); | |
149 _closureRepresentationMap[entity] = closureClass; | |
150 return closureClass; | 154 return closureClass; |
151 } | 155 } |
152 | 156 |
153 @override | 157 @override |
154 ScopeInfo getScopeInfo(Entity entity) { | 158 ScopeInfo getScopeInfo(MemberEntity entity) { |
155 // TODO(johnniwinther): Remove this check when constructor bodies a created | 159 // TODO(johnniwinther): Remove this check when constructor bodies a created |
156 // eagerly with the J-model; a constructor body should have it's own | 160 // eagerly with the J-model; a constructor body should have it's own |
157 // [ClosureRepresentationInfo]. | 161 // [ClosureRepresentationInfo]. |
158 if (entity is ConstructorBodyEntity) { | 162 if (entity is ConstructorBodyEntity) { |
159 ConstructorBodyEntity constructorBody = entity; | 163 ConstructorBodyEntity constructorBody = entity; |
160 entity = constructorBody.constructor; | 164 entity = constructorBody.constructor; |
161 } | 165 } |
162 | 166 |
163 return _scopeMap[entity] ?? getClosureRepresentationInfo(entity); | 167 return _scopeMap[entity] ?? getClosureInfoForMember(entity); |
164 } | 168 } |
165 | 169 |
166 // TODO(efortuna): Eventually capturedScopesMap[node] should always | 170 // TODO(efortuna): Eventually capturedScopesMap[node] should always |
167 // be non-null, and we should just test that with an assert. | 171 // be non-null, and we should just test that with an assert. |
168 @override | 172 @override |
169 CapturedScope getCapturedScope(MemberEntity entity) { | 173 CapturedScope getCapturedScope(MemberEntity entity) { |
170 MemberDefinition definition = _elementMap.getMemberDefinition(entity); | 174 MemberDefinition definition = _elementMap.getMemberDefinition(entity); |
171 switch (definition.kind) { | 175 switch (definition.kind) { |
172 case MemberKind.regular: | 176 case MemberKind.regular: |
173 case MemberKind.constructor: | 177 case MemberKind.constructor: |
174 case MemberKind.constructorBody: | 178 case MemberKind.constructorBody: |
175 case MemberKind.closureCall: | 179 case MemberKind.closureCall: |
176 return _capturedScopesMap[definition.node] ?? const CapturedScope(); | 180 return _capturedScopesMap[definition.node] ?? const CapturedScope(); |
177 default: | 181 default: |
178 throw failedAt(entity, "Unexpected member definition $definition"); | 182 throw failedAt(entity, "Unexpected member definition $definition"); |
179 } | 183 } |
180 } | 184 } |
181 | 185 |
182 @override | 186 @override |
183 // TODO(efortuna): Eventually capturedScopesMap[node] should always | 187 // TODO(efortuna): Eventually capturedScopesMap[node] should always |
184 // be non-null, and we should just test that with an assert. | 188 // be non-null, and we should just test that with an assert. |
185 CapturedLoopScope getCapturedLoopScope(ir.Node loopNode) => | 189 CapturedLoopScope getCapturedLoopScope(ir.Node loopNode) => |
186 _capturedScopesMap[loopNode] ?? const CapturedLoopScope(); | 190 _capturedScopesMap[loopNode] ?? const CapturedLoopScope(); |
187 | 191 |
188 @override | 192 @override |
189 ClosureRepresentationInfo getClosureRepresentationInfo(Entity entity) { | 193 ClosureRepresentationInfo getClosureInfoForMember(MemberEntity entity) { |
190 var closure = _closureRepresentationMap[entity]; | 194 var closure = _memberClosureRepresentationMap[entity]; |
191 assert( | 195 assert( |
192 closure != null, | 196 closure != null, |
193 "Corresponding closure class not found for $entity. " | 197 "Corresponding closure class not found for $entity. " |
194 "Closures found for ${_closureRepresentationMap.keys}"); | 198 "Closures found for ${_memberClosureRepresentationMap.keys}"); |
195 return closure; | 199 return closure; |
196 } | 200 } |
197 | 201 |
198 @override | 202 @override |
199 ClosureRepresentationInfo getClosureRepresentationInfoForTesting( | 203 ClosureRepresentationInfo getClosureInfo(ir.Node node) { |
200 Entity member) { | 204 var closure = _localClosureRepresentationMap[node]; |
201 return _closureRepresentationMap[member]; | 205 assert( |
| 206 closure != null, |
| 207 "Corresponding closure class not found for $node. " |
| 208 "Closures found for ${_localClosureRepresentationMap.keys}"); |
| 209 return closure; |
| 210 } |
| 211 |
| 212 @override |
| 213 ClosureRepresentationInfo getClosureInfoForMemberTesting( |
| 214 MemberEntity entity) { |
| 215 return _memberClosureRepresentationMap[entity]; |
| 216 } |
| 217 |
| 218 @override |
| 219 ClosureRepresentationInfo getClosureInfoForTesting(ir.Node node) { |
| 220 return _localClosureRepresentationMap[node]; |
202 } | 221 } |
203 } | 222 } |
204 | 223 |
205 class KernelScopeInfo { | 224 class KernelScopeInfo { |
206 final Set<ir.VariableDeclaration> localsUsedInTryOrSync; | 225 final Set<ir.VariableDeclaration> localsUsedInTryOrSync; |
207 final bool hasThisLocal; | 226 final bool hasThisLocal; |
208 final Set<ir.VariableDeclaration> boxedVariables; | 227 final Set<ir.VariableDeclaration> boxedVariables; |
209 // If boxedVariables is empty, this will be null, because no variables will | 228 // If boxedVariables is empty, this will be null, because no variables will |
210 // need to be boxed. | 229 // need to be boxed. |
211 final NodeBox capturedVariablesAccessor; | 230 final NodeBox capturedVariablesAccessor; |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
348 | 367 |
349 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); | 368 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); |
350 | 369 |
351 KernelClosureClass.fromScopeInfo( | 370 KernelClosureClass.fromScopeInfo( |
352 this.closureClassEntity, | 371 this.closureClassEntity, |
353 ir.FunctionNode closureSourceNode, | 372 ir.FunctionNode closureSourceNode, |
354 KernelScopeInfo info, | 373 KernelScopeInfo info, |
355 KernelToLocalsMap localsMap) | 374 KernelToLocalsMap localsMap) |
356 : closureEntity = closureSourceNode.parent is ir.Member | 375 : closureEntity = closureSourceNode.parent is ir.Member |
357 ? null | 376 ? null |
| 377 // TODO(johnniwinther,efortuna): This is the only place we call |
| 378 // [getLocalFunction]. Therefore the [closureEntity] doesn't need |
| 379 // to be derived from the node. |
| 380 // |
| 381 // What we should do instead: If `closureSourceNode.parent` is |
| 382 // an [ir.FunctionDeclaration] we should use the local for its |
| 383 // variable. If `closureSourceNode.parent` is an |
| 384 // [ir.FunctionExpression], we should create a fresh local. |
358 : localsMap.getLocalFunction(closureSourceNode.parent), | 385 : localsMap.getLocalFunction(closureSourceNode.parent), |
359 thisLocal = | 386 thisLocal = |
360 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null, | 387 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null, |
361 super.from(info, localsMap); | 388 super.from(info, localsMap); |
362 | 389 |
363 List<Local> get createdFieldEntities => localToFieldMap.keys.toList(); | 390 List<Local> get createdFieldEntities => localToFieldMap.keys.toList(); |
364 | 391 |
365 FieldEntity get thisFieldEntity => localToFieldMap[thisLocal]; | 392 FieldEntity get thisFieldEntity => localToFieldMap[thisLocal]; |
366 | 393 |
367 void forEachCapturedVariable(f(Local from, JField to)) { | 394 void forEachCapturedVariable(f(Local from, JField to)) { |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
543 KernelScopeInfo scopeInfo; | 570 KernelScopeInfo scopeInfo; |
544 | 571 |
545 /// Collected [CapturedScope] data for nodes. | 572 /// Collected [CapturedScope] data for nodes. |
546 Map<ir.Node, KernelCapturedScope> capturedScopesMap = | 573 Map<ir.Node, KernelCapturedScope> capturedScopesMap = |
547 <ir.Node, KernelCapturedScope>{}; | 574 <ir.Node, KernelCapturedScope>{}; |
548 | 575 |
549 /// Collected [ScopeInfo] data for nodes. | 576 /// Collected [ScopeInfo] data for nodes. |
550 Map<ir.FunctionNode, KernelScopeInfo> closuresToGenerate = | 577 Map<ir.FunctionNode, KernelScopeInfo> closuresToGenerate = |
551 <ir.FunctionNode, KernelScopeInfo>{}; | 578 <ir.FunctionNode, KernelScopeInfo>{}; |
552 } | 579 } |
OLD | NEW |