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 'closure.dart'; | 8 import 'closure.dart'; |
9 | 9 |
10 /// This builder walks the code to determine what variables are captured/free at | 10 /// This builder walks the code to determine what variables are captured/free at |
11 /// various points to build CapturedScope that can respond to queries | 11 /// various points to build CapturedScope that can respond to queries |
12 /// about how a particular variable is being used at any point in the code. | 12 /// about how a particular variable is being used at any point in the code. |
13 class CapturedScopeBuilder extends ir.Visitor { | 13 class CapturedScopeBuilder extends ir.Visitor { |
14 ir.TreeNode _currentLocalFunction; | 14 ir.TreeNode _currentLocalFunction; |
15 | 15 |
16 ScopeModel _model; | 16 ScopeModel _model; |
17 | 17 |
18 /// A map of each visited call node with the associated information about what | 18 /// A map of each visited call node with the associated information about what |
19 /// variables are captured/used. Each ir.Node key corresponds to a scope that | 19 /// variables are captured/used. Each ir.Node key corresponds to a scope that |
20 /// was encountered while visiting a closure (initially called through | 20 /// was encountered while visiting a closure (initially called through |
21 /// [translateLazyIntializer] or [translateConstructorOrProcedure]). | 21 /// [translateLazyIntializer] or [translateConstructorOrProcedure]). |
22 Map<ir.Node, KernelCapturedScope> get _scopesCapturedInClosureMap => | 22 Map<ir.Node, KernelCapturedScope> get _scopesCapturedInClosureMap => |
23 _model.capturedScopesMap; | 23 _model.capturedScopesMap; |
24 | 24 |
25 /// A map of the nodes that we have flagged as necessary to generate closure | 25 /// A map of the nodes that we have flagged as necessary to generate closure |
26 /// classes for in a later stage. We map that node to information ascertained | 26 /// classes for in a later stage. We map that node to information ascertained |
27 /// about variable usage in the surrounding scope. | 27 /// about variable usage in the surrounding scope. |
28 Map<ir.FunctionNode, KernelScopeInfo> get _closuresToGenerate => | 28 Map<ir.TreeNode, KernelScopeInfo> get _closuresToGenerate => |
29 _model.closuresToGenerate; | 29 _model.closuresToGenerate; |
30 | 30 |
31 /// The local variables that have been declared in the current scope. | 31 /// The local variables that have been declared in the current scope. |
32 List<ir.VariableDeclaration> _scopeVariables; | 32 List<ir.VariableDeclaration> _scopeVariables; |
33 | 33 |
34 /// Pointer to the context in which this closure is executed. | 34 /// Pointer to the context in which this closure is executed. |
35 /// For example, in the expression `var foo = () => 3 + i;`, the executable | 35 /// For example, in the expression `var foo = () => 3 + i;`, the executable |
36 /// context as we walk the nodes in that expression is the ir.Field `foo`. | 36 /// context as we walk the nodes in that expression is the ir.Field `foo`. |
37 ir.TreeNode _executableContext; | 37 ir.TreeNode _executableContext; |
38 | 38 |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 scope.boxedVariables, | 214 scope.boxedVariables, |
215 scope.capturedVariablesAccessor, | 215 scope.capturedVariablesAccessor, |
216 boxedLoopVariables, | 216 boxedLoopVariables, |
217 scope.context, | 217 scope.context, |
218 scope.localsUsedInTryOrSync, | 218 scope.localsUsedInTryOrSync, |
219 scope.freeVariables, | 219 scope.freeVariables, |
220 scope.hasThisLocal); | 220 scope.hasThisLocal); |
221 } | 221 } |
222 | 222 |
223 void visitInvokable(ir.TreeNode node) { | 223 void visitInvokable(ir.TreeNode node) { |
| 224 assert(node is ir.Member || |
| 225 node is ir.FunctionExpression || |
| 226 node is ir.FunctionDeclaration); |
224 bool oldIsInsideClosure = _isInsideClosure; | 227 bool oldIsInsideClosure = _isInsideClosure; |
225 ir.TreeNode oldExecutableContext = _executableContext; | 228 ir.TreeNode oldExecutableContext = _executableContext; |
226 KernelScopeInfo oldScopeInfo = _currentScopeInfo; | 229 KernelScopeInfo oldScopeInfo = _currentScopeInfo; |
227 ir.TreeNode oldLocalFunction = _currentLocalFunction; | 230 ir.TreeNode oldLocalFunction = _currentLocalFunction; |
228 | 231 |
229 // _outermostNode is only null the first time we enter the body of the | 232 // _outermostNode is only null the first time we enter the body of the |
230 // field, constructor, or method that is being analyzed. | 233 // field, constructor, or method that is being analyzed. |
231 _isInsideClosure = _outermostNode != null; | 234 _isInsideClosure = _outermostNode != null; |
232 _executableContext = node; | 235 _executableContext = node; |
233 | 236 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 /// Return true if [variable]'s context is the same as the current executable | 270 /// Return true if [variable]'s context is the same as the current executable |
268 /// context. | 271 /// context. |
269 bool _inCurrentContext(ir.VariableDeclaration variable) { | 272 bool _inCurrentContext(ir.VariableDeclaration variable) { |
270 ir.TreeNode node = variable; | 273 ir.TreeNode node = variable; |
271 while (node != _outermostNode && node != _executableContext) { | 274 while (node != _outermostNode && node != _executableContext) { |
272 node = node.parent; | 275 node = node.parent; |
273 } | 276 } |
274 return node == _executableContext; | 277 return node == _executableContext; |
275 } | 278 } |
276 | 279 |
277 void translateLazyInitializer(ir.Field field) { | 280 @override |
| 281 void visitField(ir.Field field) { |
278 visitInvokable(field); | 282 visitInvokable(field); |
279 } | 283 } |
280 | 284 |
281 void translateConstructorOrProcedure(ir.Node constructorOrProcedure) { | 285 @override |
282 constructorOrProcedure.accept(this); | 286 void visitConstructor(ir.Constructor constructor) { |
| 287 visitInvokable(constructor); |
283 } | 288 } |
284 | 289 |
285 void visitFunctionNode(ir.FunctionNode functionNode) { | 290 @override |
286 visitInvokable(functionNode); | 291 void visitProcedure(ir.Procedure procedure) { |
| 292 visitInvokable(procedure); |
| 293 } |
| 294 |
| 295 @override |
| 296 void visitFunctionExpression(ir.FunctionExpression functionExpression) { |
| 297 visitInvokable(functionExpression); |
| 298 } |
| 299 |
| 300 @override |
| 301 void visitFunctionDeclaration(ir.FunctionDeclaration functionDeclaration) { |
| 302 visitInvokable(functionDeclaration); |
287 } | 303 } |
288 } | 304 } |
OLD | NEW |